我們已經(jīng)掌握了App從創(chuàng)建進(jìn)程到實(shí)例化ActivityThread的過程缰儿,接下來繼續(xù)研究Activity的啟動(dòng)過程。
從ActivityThread#handleLaunchActivity說起
Activity的實(shí)例化是在ActivityThread#handleLaunchActivity中完成的,相關(guān)代碼如下:
/frameworks/base/core/java/android/app/ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...
// 創(chuàng)建Activity茂缚,并調(diào)用一些方法
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
...
// resume
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
...
} else {
...
}
}
Activity的onCreate和onStart都是在performLaunchActivity方法中完成的,代碼如下:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
} catch (Exception e) {
...
}
try {
...
if (activity != null) {
// Activity中的Context是在這里創(chuàng)建的
Context appContext = createBaseContextForActivity(r, activity);
...
// 將一系列字段attach到Activity中
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, window);
...
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
// 調(diào)用onCreate
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
if (!r.activity.mFinished) {
// 調(diào)用onStart
activity.performStart();
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
}
} else if (r.state != null) {
// 保存的狀態(tài)恢復(fù)
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnPostCreate(activity, r.state,
r.persistentState);
} else {
// 調(diào)用onPostCreate
mInstrumentation.callActivityOnPostCreate(activity, r.state);
}
...
}
}
r.paused = true;
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
...
}
return activity;
}
這里首先執(zhí)行了Activity#attach方法字币,代碼如下:
/frameworks/base/core/java/android/app/Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
// 創(chuàng)建一個(gè)Window
mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
if (voiceInteractor != null) {
if (lastNonConfigurationInstances != null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
Looper.myLooper());
}
}
// 給Window配置WindowManager蕾哟,這是一個(gè)系統(tǒng)服務(wù)
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
這里我們主要關(guān)注mWindow的初始化和WindowManager的配置一忱,mWindow是一個(gè)PhoneWindow的實(shí)例,其中傳給它的參數(shù)window目前為null谭确,它的構(gòu)造方法如下:
/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
public PhoneWindow(Context context, Window preservedWindow) {
this(context);
// Only main activity windows use decor context, all the other windows depend on whatever
// context that was given to them.
mUseDecorContext = true;
if (preservedWindow != null) {
// 如果preservedWindow不為空帘营,mDecor是直接獲取的,應(yīng)該和恢復(fù)有關(guān)
mDecor = (DecorView) preservedWindow.getDecorView();
...
}
...
}
可以看到此時(shí)逐哈,只是創(chuàng)建了一個(gè)PhoneWindow芬迄,mDecor還是空的。WindowManager是一個(gè)系統(tǒng)服務(wù)昂秃,通信的方式依然是Binder禀梳,這里不再追蹤,獲取到之后肠骆,通過mWindow.setWindowManager方法完成配置算途,代碼如下:
// /frameworks/base/core/java/android/view/Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
...
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
// /frameworks/base/core/java/android/view/WindowManagerImpl.java
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
可見,最終設(shè)置給mWindow對(duì)象的WindowManager是WindowManagerImpl實(shí)例哗戈。
繼續(xù)回到ActivityThread#performLaunchActivity郊艘,接下來調(diào)用的是mInstrumentation.callActivityOnCreate(activity, r.state)方法荷科,代碼如下:
/frameworks/base/core/java/android/app/Instrumentation.java
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
/frameworks/base/core/java/android/app/Activity.java
final void performCreate(Bundle icicle) {
restoreHasCurrentPermissionRequest(icicle);
onCreate(icicle);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
if (mLastNonConfigurationInstances != null) {
mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
}
if (mActivityInfo.parentActivityName != null) {
if (mActionBar == null) {
mEnableDefaultActionBarUp = true;
} else {
mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
}
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.fragments : null);
}
mFragments.dispatchCreate();
getApplication().dispatchActivityCreated(this, savedInstanceState);
if (mVoiceInteractor != null) {
mVoiceInteractor.attachActivity(this);
}
mCalled = true;
}
final void performCreateCommon() {
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
mFragments.dispatchActivityCreated();
mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
}
這里處理了Fragment的恢復(fù)工作唯咬,還調(diào)用了Application#dispatchActivityCreated方法以方便記錄Activity的生命周期纱注,包括入場Transition動(dòng)畫也是這時(shí)候處理的。不過我們?cè)?strong>Activity#onCreate中還會(huì)調(diào)用一個(gè)方法:setContentView胆胰,用來加載布局狞贱,否則Activity只有一個(gè)PhoneWindow做不了任何事情,我們需要帶上這個(gè)方法一起分析蜀涨。setContentView會(huì)在上述onCreate執(zhí)行完成后調(diào)用瞎嬉,它的代碼如下:
public void setContentView(@LayoutRes int layoutResID) {
// 這里的getWindow就是PhoneWindow
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
可見,我們?cè)O(shè)置的布局是加載到了PhoneWindow中的厚柳,相關(guān)代碼如下:
/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
// mContentParent是我們?cè)O(shè)置的layout的父布局
if (mContentParent == null) {
// 初始化Decor
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
...
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
...
}
先看下Decor是如何完成初始化的:
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
...
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
...
}
}
protected DecorView generateDecor(int featureId) {
// System process doesn't have application context and in that case we need to directly use
// the context we have. Otherwise we want the application context, so we don't cling to the
// activity.
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, getContext().getResources());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
return new DecorView(context, featureId, this, getAttributes());
}
protected ViewGroup generateLayout(DecorView decor) {
...
// android.R.id.content
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
int layoutResource;
...
mDecor.startChanging();
// 根據(jù)不同的Feature設(shè)置不同的布局文件
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
...
return contentParent;
}
至此DecorView創(chuàng)建完畢氧枣,一些初始化工作也完成了,接下來再次回到PhoneWindow#setContentView方法别垮,這里將我們的布局通過mLayoutInflater.inflate(layoutResID, mContentParent)方法添加到了mContentParent中便监。相關(guān)代碼如下:
/frameworks/base/core/java/android/view/LayoutInflater.java
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
...
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
解析XML的過程我們就不關(guān)注了,繼續(xù)向下看:
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
...
try {
// Look for the root node.
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
...
if (TAG_MERGE.equals(name)) {
...
rInflate(parser, root, inflaterContext, attrs, false);
} else {
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
...
// Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, true);
...
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
...
}
return result;
}
}
這里我們看到兩個(gè)函數(shù):rInflate和rInflateChildren碳想,這兩個(gè)函數(shù)我們要結(jié)合起來看烧董,代碼如下:
final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
boolean finishInflate) throws XmlPullParserException, IOException {
rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
}
void rInflate(XmlPullParser parser, View parent, Context context,
AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {
final int depth = parser.getDepth();
int type;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String name = parser.getName();
if (TAG_REQUEST_FOCUS.equals(name)) {
parseRequestFocus(parser, parent);
} else if (TAG_TAG.equals(name)) {
parseViewTag(parser, parent, attrs);
} else if (TAG_INCLUDE.equals(name)) {
if (parser.getDepth() == 0) {
throw new InflateException("<include /> cannot be the root element");
}
parseInclude(parser, context, parent, attrs);
} else if (TAG_MERGE.equals(name)) {
throw new InflateException("<merge /> must be the root element");
} else {
final View view = createViewFromTag(parent, name, context, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflateChildren(parser, view, attrs, true);
viewGroup.addView(view, params);
}
}
if (finishInflate) {
parent.onFinishInflate();
}
}
可以看到,這兩個(gè)函數(shù)胧奔,在循環(huán)地互相調(diào)用逊移,直到所有的View都解析完畢,最后調(diào)用到parent.onFinishInflate()方法龙填,完成inflate過程胳泉。
經(jīng)過以上步驟后,Activity就創(chuàng)建完畢了岩遗,于此同時(shí)DecorView和我們的布局文件都初始化完成了胶背,但是DecorView還沒有添加到Window中,不能進(jìn)行顯示喘先。我們?cè)俅位氐?strong>ActivityThread#performLaunchActivity中钳吟,接下來就該是activity.performStart()了,代碼如下:
/frameworks/base/core/java/android/app/Activity.java
final void performStart() {
mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
mFragments.noteStateNotSaved();
mCalled = false;
mFragments.execPendingActions();
mInstrumentation.callActivityOnStart(this);
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onStart()");
}
mFragments.dispatchStart();
mFragments.reportLoaderStart();
...
}
這里看到了一點(diǎn)Fragment和Activity生命周期的問題窘拯,我們以后再來研究它红且。Instrumentation#callActivityOnStart和Activity#onStart并沒有做什么事,這里還是粘貼下它的代碼:
// /frameworks/base/core/java/android/app/Instrumentation.java
public void callActivityOnStart(Activity activity) {
activity.onStart();
}
// /frameworks/base/core/java/android/app/Activity.java
protected void onStart() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
mCalled = true;
mFragments.doLoaderStart();
getApplication().dispatchActivityStarted(this);
}
繼續(xù)回到ActivityThread#performLaunchActivity涤姊,接下來調(diào)用了ActivityThread#handleResumeActivity方法暇番,代碼如下:
/frameworks/base/core/java/android/app/ActivityThread.java
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
...
// TODO Push resumeArgs into the activity for consideration
r = performResumeActivity(token, clearHide, reason);
if (r != null) {
final Activity a = r.activity;
...
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
boolean willBeVisible = !a.mStartedActivity;
...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
// 先將Decor不可見
decor.setVisibility(View.INVISIBLE);
...
// Window已經(jīng)恢復(fù),之前保持的狀態(tài)要改變
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
...
}
if (a.mVisibleFromClient && !a.mWindowAdded) {
a.mWindowAdded = true;
// 把Decor加載到Window中
wm.addView(decor, l);
}
// If the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
} else if (!willBeVisible) {
...
}
// Get rid of anything left hanging around.
cleanUpPendingRemoveWindows(r, false /* force */);
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible
&& r.activity.mDecor != null && !r.hideForNow) {
...
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
// 可以可見了
r.activity.makeVisible();
}
}
...
// Tell the activity manager we have resumed.
if (reallyResume) {
try {
ActivityManagerNative.getDefault().activityResumed(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
} else {
...
}
}
這里處理了很多工作思喊,首先通過performResumeActivity調(diào)用Activity#onResume壁酬,使得Activity進(jìn)入onResume狀態(tài),然后將DecorView添加到Window中并顯示出來。先看下performResumeActivity的實(shí)現(xiàn):
public final ActivityClientRecord performResumeActivity(IBinder token,
boolean clearHide, String reason) {
ActivityClientRecord r = mActivities.get(token);
if (localLOGV) Slog.v(TAG, "Performing resume of " + r
+ " finished=" + r.activity.mFinished);
if (r != null && !r.activity.mFinished) {
if (clearHide) {
r.hideForNow = false;
r.activity.mStartedActivity = false;
}
try {
...
r.activity.performResume();
...
} catch (Exception e) {
...
}
}
return r;
}
繼續(xù)跟蹤舆乔,到了Activity#performResume方法岳服,代碼如下:
final void performResume() {
performRestart();
...
// mResumed is set by the instrumentation
mInstrumentation.callActivityOnResume(this);
...
// Now really resume, and install the current status bar and menu.
mCalled = false;
mFragments.dispatchResume();
mFragments.execPendingActions();
onPostResume();
...
}
final void performRestart() {
...
// Activity是Stop時(shí)才會(huì)執(zhí)行以下代碼
if (mStopped) {
mStopped = false;
...
mCalled = false;
mInstrumentation.callActivityOnRestart(this);
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onRestart()");
}
// onRestart之后立即執(zhí)行onStart
performStart();
}
}
然后通過Instrumentation#callActivityOnResume再調(diào)用Activity#onResume方法,之后Activity就進(jìn)入了onResume狀態(tài)希俩。最后吊宋,當(dāng)Activity確實(shí)Resume之后,還通知了ActivityManagerService以進(jìn)行一些其他操作颜武。
接下來璃搜,我們看下Window加載DecorView的過程,它是通過設(shè)置給Window的WindowManager完成的鳞上,也就是WindowManagerImpl對(duì)象这吻,相關(guān)代碼如下:
/frameworks/base/core/java/android/view/WindowManagerImpl.java
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
可以看到DecorView添加到了一個(gè)全局的WindowManagerGlobal中,相關(guān)代碼如下:
/frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
synchronized (mLock) {
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
...
}
}
WindowManagerGlobal中保存了一系列的ViewRootImpl實(shí)例篙议,我們每增加一個(gè)布局橘原,就會(huì)新建一個(gè)ViewRootImpl對(duì)象,接下來看它的setView方法涡上,代碼如下:
/frameworks/base/core/java/android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
// if確保了只有一個(gè)View
if (mView == null) {
mView = view;
...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
...
try {
...
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} catch (RemoteException e) {
...
}
...
view.assignParent(this);
...
}
}
}
這里首先調(diào)用了requestLayout方法渲染頁面趾断,然后通過mWindowSession.addToDisplay將頁面添加到WindowManagerService中。我們先看前一個(gè)方法吩愧,代碼如下:
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
在這里看到checkThread不禁眼前一亮芋酌,它的實(shí)現(xiàn)如下:
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
這就是說,直到onResume之后雁佳,Activity才會(huì)檢查是否在非UI線程更新UI脐帝。繼續(xù)看其他部分,代碼如下:
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
這里使用了MessageQueue#postSyncBarrier方法糖权,這個(gè)方式稱為同步屏障堵腹,可以通過此發(fā)送一個(gè)異步消息,這個(gè)消息將會(huì)優(yōu)先被執(zhí)行星澳,具體的解釋可以看我的文章:Android源碼分析之Handler疚顷。接下來部分代碼會(huì)跳轉(zhuǎn)至Native完成,最終會(huì)執(zhí)行到mTraversalRunnable這個(gè)回調(diào)里禁偎,代碼如下:
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
也就是說系統(tǒng)會(huì)盡快執(zhí)行TraversalRunnable#run方法腿堤,代碼如下:
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
...
performTraversals();
...
}
}
首先會(huì)解除屏障,然后執(zhí)行performTraversals方法如暖,從這里開始笆檀,View將會(huì)進(jìn)行measure、layout盒至、draw等過程酗洒。限于篇幅士修,下一篇文章繼續(xù)分析。