前言:
在上兩篇文章中對setContentView()
是如何將我們的內(nèi)容視圖添加到系統(tǒng)提供的根視圖中以及PhoneWindow的創(chuàng)建等做了粗略的分析,且這個時候內(nèi)容視圖還完全處于內(nèi)存中 我們是還看不見的,本篇趁熱打鐵繼續(xù)跟進 將要了解Activity是如何將DecorView添加到Window中 以及是如何將DecorView繪制到屏幕上的
分析要點:
老規(guī)矩 先來張Activity啟動流程圖:
都知道系統(tǒng)源碼中有一個全局的Handler 不管是Activity的啟動還是Service的啟動或綁定 亦或廣播的注冊 都會由它發(fā)送消息處理,而這個Handler對消息的處理就在ActivityThread類中 本文也將從ActivityThread中著手去分析Activity啟動后生命周期是如何執(zhí)行的蚣驼。
源碼閱讀:
因?qū)τ趕tartActivity()和通過Launch啟動App的啟動流程尚且不熟悉 所以這里直接跳到Activity已經(jīng)開始啟動的流程著手分析 首先來到ActivityThread#handleLaunchActivity() 所有Activity的啟動都會調(diào)用這里 同時也會只撿要緊的函數(shù)看
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
unscheduleGcIdler();
mSomeActivitiesChanged = true;
if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
// WindowManagerGlobal初始化工作 這個WindowManagerGlobal是非常重要的一個類
WindowManagerGlobal.initialize();
//Activity就是在這里創(chuàng)建的
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
//Activity的onResume() 以及內(nèi)容視圖的繪制就是從這個函數(shù)開始的
handleResumeActivity(r.token, false, r.isForward,!r.activity.mFinished && !r.startsNotResumed);
}
}
先看Activity是如何創(chuàng)建的
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
//這里通過反射的方式創(chuàng)建Activity
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
//這里調(diào)用了activity#attach()進行PhoneWindow的創(chuàng)建以及一些Cllback監(jiān)聽的初始化和非常重要的WindowManagerImpl初始化等操作
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
//Activity的onCreate()這里被調(diào)用 區(qū)別就是參數(shù)不同
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
r.activity = activity;
r.stopped = true;
//Activity的onStart()在這里被調(diào)用
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
.................................
return activity;
}
mInstrumentation.callActivityOnCreate()
Activtiy#onCreate()和Activity#onStart()
//這個Instrumentation類似于AppCompatActivity中的AppCompatDelegate一樣是一個代理類
public class Instrumentation {
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
//onCreate()
activity.performCreate(icicle);
postPerformCreate(activity);
}
//Activity#onStart()
public void callActivityOnStart(Activity activity) {
activity.onStart();
}
}
.................分割線................
// 跟進activity.performCreate(icicle)
class Activity{
//一個參數(shù)
final void performCreate(Bundle icicle) {
restoreHasCurrentPermissionRequest(icicle);
//執(zhí)行OnonCreate()
onCreate(icicle);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
//2個參數(shù)
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
restoreHasCurrentPermissionRequest(icicle);
//執(zhí)行OnonCreate()
onCreate(icicle, persistentState);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
final void performStart() {
mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
mFragments.noteStateNotSaved();
mCalled = false;
mFragments.execPendingActions();
//通過調(diào)用Instrumentation類的callActivityOnStart執(zhí)行OnStart()
mInstrumentation.callActivityOnStart(this);
mFragments.dispatchStart();
mFragments.reportLoaderStart();
........
}
}
Activity創(chuàng)建好了 并且也執(zhí)行到onStart() 再返回去看Activity的onResume()以及內(nèi)容視圖的繪制過程
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// Activity#onResume()在這里執(zhí)行 且此時內(nèi)容還未繪制 也驗證了onResume()后視圖可見 是一個錯誤的觀念 至少需要等一會
ActivityClientRecord r = performResumeActivity(token, clearHide);
/*****************重點將從這里開始**************************/
if (r.window == null && !a.mFinished && willBeVisible) {
//獲取Activity中創(chuàng)建的Window對象
r.window = r.activity.getWindow();
//獲取Window中的DecorView
View decor = r.window.getDecorView();
//INVISIBLE雖然不可見 但是卻能占據(jù)window空間
decor.setVisibility(View.INVISIBLE);
//這里獲取WindowManager的實現(xiàn)類WindowManagerImpl這是一個很重要的類
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
//這一步執(zhí)行將DecorView添加到Window窗口中和針對DecorView的測量 布局 繪制操作
wm.addView(decor, l);
}
}
....................
}
先看Activity的onResume()是如何執(zhí)行的
public final ActivityClientRecord performResumeActivity(IBinder token,
boolean clearHide) {
............
//onResume()在這里被執(zhí)行
r.activity.performResume();
............
return r;
}
DecorView是如何添加到Window中的财异? 且WindowManagerImpl是在Activity#attach()時初始化的 就要從WindowManagerImpl類開始分析 上面也是調(diào)用的 WindowManagerImpl的addView()
public final class WindowManagerImpl implements WindowManager {
//WindowManagerGlobal
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
}
/*******************WindowManagerGlobal************************/
public final class WindowManagerGlobal {
//這里聲明一些集合 來緩存我們加載過的view 在下次使用的時候 見會提高程序的執(zhí)行速度
private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
private final ArrayList<WindowManager.LayoutParams> mParams =
new ArrayList<WindowManager.LayoutParams>();
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
mRoots.get(index).doDie();
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
//這個view就是DecorView
mViews.add(view);
//ViewRootImpl 繪制好了View
mRoots.add(root);
//Window#Params
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try {
/*****************從這里開始 就開啟正式的繪制流程*******/
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}
繼續(xù)深入 ViewRootImpl.setView()
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...........................................
//執(zhí)行繪制操作
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
//這里使用IPC WMS將完成窗口的添加過程 這塊我也不太下熟悉就跳過了
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
//這句代碼也很重要 將ViewRootImpl設(shè)置為DecorView的 ViewParent
view.assignParent(this);
}
requestLayout()
繪制流程
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//Choreographer類中有一個Handler通過發(fā)送消息執(zhí)行TraversalRunnable的run()方法
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
.........
performTraversals();
..........
}
//到這函數(shù) 針對DecorView的測量 布局 繪制 都將完成
private void performTraversals() {
.............
if (!mStopped || mReportNextDraw) {
//確定測量模式和測量規(guī)格
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
(relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
|| mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
//將調(diào)用DecorView的Measure()
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
//將調(diào)用DecorView的Layout()
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
//將調(diào)用DecorView的Draw()
performDraw();
}
測量 布局 繪制完成 再通過WMS完成窗口的添加過程 到此DecorView才真正顯示到我們的屏幕上了
最后再多看一眼view.assignParent(this);將ViewRootImpl設(shè)置為DecorView的 ViewParent 這樣的目的是什么
class View{
void assignParent(ViewParent parent) {
if (mParent == null) {
mParent = parent;
} else if (parent == null) {
mParent = null;
}
//當(dāng)我們調(diào)用View的 requestLayout()
@CallSuper
public void requestLayout() {
if (mMeasureCache != null) mMeasureCache.clear();
if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {
// Only trigger request-during-layout logic if this is the view requesting it,
// not the views in its parent hierarchy
ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot != null && viewRoot.isInLayout()) {
if (!viewRoot.requestLayoutDuringLayout(this)) {
return;
}
}
mAttachInfo.mViewRequestingLayout = this;
}
mPrivateFlags |= PFLAG_FORCE_LAYOUT;
mPrivateFlags |= PFLAG_INVALIDATED;
if (mParent != null && !mParent.isLayoutRequested()) {
//將會一直獲取到父容器的 mParent.requestLayout();
mParent.requestLayout();
}
}
}
到這里就很明白了平時我們在調(diào)用View的requestLayout()
進行重新測量 布局 繪制時 會一直走到 ViewRootImpl的requestLayout()函數(shù)將DecorView重新測量 布局 繪制 由此看出在不是很必要的情況下不能直接調(diào)用該函數(shù)來刷新視圖 因為這個過程是很耗CUP的。