再遇Looper&構(gòu)造ActivityClientRecord
上一篇文章分析到:app.thread.scheduleLaunchActivity會(huì)跨進(jìn)程通知App進(jìn)程啟動(dòng)Activity估灿。thread是android.app.ActivityThread.ApplicationThread類(lèi)型的實(shí)例虾攻。
繼續(xù)分析android.app.ActivityThread.ApplicationThread#scheduleLaunchActivity:
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profileFile = profileName;
r.profileFd = profileFd;
r.autoStopProfiler = autoStopProfiler;
//系統(tǒng)信息相關(guān)內(nèi)容,場(chǎng)景無(wú)關(guān)
updatePendingConfiguration(curConfig);
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
}
參數(shù)挺多的胖秒,都是用于構(gòu)造ActivityClientRecord實(shí)例庐杨,前幾篇文章講過(guò)ActivityClientRecord是用來(lái)記錄App進(jìn)程側(cè)的Activity的斜棚,我們之前使用過(guò)MainActivity的ActivityClientRecord酱塔,而這次構(gòu)造的是屬于TargetActivity的ActivityClientRecord驮捍。
private void queueOrSendMessage(int what, Object obj) {
//是不是有點(diǎn)眼熟
queueOrSendMessage(what, obj, 0, 0);
}
是的,之前在pause掉MainActivity的時(shí)候就是調(diào)用的它玖翅,往looper里面拋信息的翼馆。這里思考一個(gè)問(wèn)題為什么要用looper去異步執(zhí)行?而不是直接順序同步執(zhí)行金度?
稍微思考一下即可得到答案:Binder是同步調(diào)用的应媚,也就是說(shuō)執(zhí)行到這AMS還在等待App進(jìn)程執(zhí)行完成呢,同樣startActivity最初的調(diào)用處還在等待AMS執(zhí)行完成呢猜极,如果不用looper異步執(zhí)行中姜,那么系統(tǒng)進(jìn)程會(huì)一直被掛在那里,這哪能行呢跟伏,AMS還要處理其他的startActivity或者其他的跨進(jìn)程調(diào)用呢丢胚。
因此當(dāng)系統(tǒng)進(jìn)程通知App進(jìn)程執(zhí)行任務(wù)時(shí),都是通過(guò)looper的方式來(lái)執(zhí)行的酬姆。就好比一個(gè)母豬十個(gè)崽嗜桌,奶就在那,已經(jīng)告訴你吃奶了辞色,愛(ài)吃不吃骨宠,還有剩下九個(gè)崽要管呢浮定。
android.app.ActivityThread.H#handleMessage:
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
...
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
...
} break;
...
}
onCreate、onStart层亿、onResume的準(zhǔn)備工作
繼續(xù)分析android.app.ActivityThread#getPackageInfoNoCheck:
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
CompatibilityInfo compatInfo) {
return getPackageInfo(ai, compatInfo, null, false, true);
}
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
synchronized (mPackages) {
WeakReference<LoadedApk> ref;
//先從內(nèi)存緩存里取Apk信息
if (includeCode) {
ref = mPackages.get(aInfo.packageName);
} else {
ref = mResourcePackages.get(aInfo.packageName);
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
//取不到的話(huà)創(chuàng)建一個(gè)桦卒,并且放在內(nèi)存緩存里,下次可以直接用
if (packageInfo == null || (packageInfo.mResources != null
&& !packageInfo.mResources.getAssets().isUpToDate())) {
...
packageInfo =
new LoadedApk(this, aInfo, compatInfo, this, baseLoader,
securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0);
if (includeCode) {
mPackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
} else {
mResourcePackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
}
}
return packageInfo;
}
}
具體如何執(zhí)行不再分析匿又,該函數(shù)就是獲得了Apk的信息方灾。賦值給了r.packageInfo。
android.app.ActivityThread#handleLaunchActivity:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward);
...
} else {
...
}
}
onCreate碌更、onStart的調(diào)用
函數(shù)代碼比較長(zhǎng)裕偿,實(shí)際上場(chǎng)景相關(guān)的只有兩行,分別是performLaunchActivity和handleResumeActivity的調(diào)用痛单。
先分析android.app.ActivityThread#performLaunchActivity嘿棘。
函數(shù)比較長(zhǎng)(難道google編碼規(guī)范,沒(méi)有限制函數(shù)行數(shù)嗎旭绒,100多行了)鸟妙,分兩段進(jìn)行分析,第一段:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
//若沒(méi)有拿到Apk信息挥吵,再次嘗試取拿重父,不走這,之前已經(jīng)拿到了Apk信息忽匈,上文分析過(guò)
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
//當(dāng)前場(chǎng)景的組件名不會(huì)為null房午。若是null,還會(huì)嘗試向PMS查找
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
...
Activity activity = null;
try {
//拿到ClassLoader
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//利用ClassLoader和組件名(TargetActivity類(lèi)全稱(chēng))脉幢,實(shí)例化TargetActivity
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
//不知道干啥用的歪沃,場(chǎng)景無(wú)關(guān)
StrictMode.incrementExpectedActivityCount(activity.getClass());
//一些賦值
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
...
}
//第一段結(jié)束
...
}
第一段核心內(nèi)容:創(chuàng)建Activity實(shí)例嗦锐。
android.app.Instrumentation#newActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent):
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
創(chuàng)建過(guò)程很簡(jiǎn)單嫌松。
繼續(xù)分析系第二段:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
//第二段開(kāi)始
try {
//拿到App進(jìn)程對(duì)應(yīng)的Application對(duì)象
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
if (activity != null) {
//設(shè)置Activity相關(guān)的Context內(nèi)容
ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo, r.token, this);
appContext.setOuterContext(activity);
...
//把一些信息設(shè)置個(gè)Activity,其中Activity的”身份證”mToken就是在這里設(shè)置的
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config);
...
activity.mCalled = false;
//調(diào)用onCreate
mInstrumentation.callActivityOnCreate(activity, r.state);
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
//把Activity記錄給ActivityClientRecord
r.activity = activity;
//還沒(méi)有resume奕污,先設(shè)置成true
r.stopped = true;
//onCreate調(diào)用后萎羔,馬上調(diào)用onStart
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
...
}
//還沒(méi)有resume,先設(shè)置成true
r.paused = true;
//把ActivityClientRecord記錄下來(lái)碳默。前面文章中使用過(guò)mActivities查找MainActivity的ActivityClientRecord
mActivities.put(r.token, r);
}
...
return activity;
}
這函數(shù)主要干了一下幾件事:
- 創(chuàng)建Activity實(shí)例
- 給Activity設(shè)置好Context
- 設(shè)置attach一些Activity需要的信息
- 調(diào)用Activity的onCreate方法
- 調(diào)用Activity的onStart方法
- 把Activity實(shí)例記錄下來(lái)贾陷,方便后續(xù)查找
這里再簡(jiǎn)單分析下onCreate的調(diào)用android.app.Instrumentation#callActivityOnCreate:
public void callActivityOnCreate(Activity activity, Bundle icicle) {
...
activity.performCreate(icicle);
...
}
final void performCreate(Bundle icicle) {
onCreate(icicle);
...
//Fragment的onActivityCreated分發(fā)
mFragments.dispatchActivityCreated();
}
調(diào)用和onPause類(lèi)似,也是用過(guò)Instrumentation進(jìn)行調(diào)用嘱根,也會(huì)驗(yàn)證是否調(diào)用了super方法髓废。不再贅述。
在onCreate里會(huì)調(diào)用setContentView來(lái)設(shè)置布局该抒。
android.app.Activity#setContentView(int):
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
initActionBar();
}
getWindow()返回的是com.android.internal.policy.impl.PhoneWindow類(lèi)型的慌洪。
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
// 構(gòu)造DecorView
installDecor();
} else {
mContentParent.removeAllViews();
}
// 根據(jù)xml創(chuàng)建View樹(shù)
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
setContentView構(gòu)造DecorView和View樹(shù),這里不是本文重點(diǎn),不再分析冈爹。
onResume的調(diào)用
繼續(xù)回到handleLaunchActivity中涌攻,分析:
android.app.ActivityThread#handleResumeActivity:
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
...
// 執(zhí)行onResume
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
if (localLOGV) Slog.v(
TAG, "Resume " + r + " started activity: " +
a.mStartedActivity + ", hideForNow: " + r.hideForNow
+ ", finished: " + a.mFinished);
final int forwardBit = isForward ?
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
// 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 (!willBeVisible) {
...
}
//記錄Window、DecorView等频伤。最后把View加進(jìn)Window(使用ViewRootImpl進(jìn)行add)
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
//暫時(shí)設(shè)置成INVISIBLE
decor.setVisibility(View.INVISIBLE);
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;
wm.addView(decor, l);
}
} else if (!willBeVisible) {
...
}
...
// 里面會(huì)把DecorView設(shè)置成VISIBLE
r.activity.makeVisible();
}
代碼比較長(zhǎng)恳谎,但場(chǎng)景有用的就兩步:
- 調(diào)用onResume函數(shù)
- 記錄Window、DecorView等到ActivityClientRecord里憋肖,并把View添加進(jìn)Window
下面我們繼續(xù)分析android.app.ActivityThread#performResumeActivity:
public final ActivityClientRecord performResumeActivity(IBinder token,
boolean clearHide) {
//根據(jù)token拿ActivityClientRecord因痛,老套路了
ActivityClientRecord r = mActivities.get(token);
...
//顯而易見(jiàn),走這兒
if (r != null && !r.activity.mFinished) {
//clearHide傳入的是true岸更,設(shè)置了一些變量婚肆,一時(shí)半會(huì)兒用不到
if (clearHide) {
r.hideForNow = false;
r.activity.mStartedActivity = false;
}
try {
...
//里面用調(diào)用onResume
r.activity.performResume();
...
//這倆在調(diào)用onCreate的時(shí)候都設(shè)置成true了,現(xiàn)在已經(jīng)resume了坐慰,設(shè)置成false
r.paused = false;
r.stopped = false;
r.state = null;
} catch (Exception e) {
...
}
}
return r;
}
過(guò)程很簡(jiǎn)單较性,注釋里已經(jīng)能描述清楚了。主要是調(diào)用onResume和設(shè)置狀態(tài)值结胀。
繼續(xù)看下android.app.Activity#performResume:
final void performResume() {
//里面會(huì)調(diào)用onRestart聲明和周期函數(shù)
performRestart();
...
mCalled = false;
//依然是老套路赞咙,通過(guò)Instrumentation調(diào)用onResume,并且必須調(diào)用super方法
mInstrumentation.callActivityOnResume(this);
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onResume()");
}
mCalled = false;
//Fragement分發(fā)resume
mFragments.dispatchResume();
...
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onPostResume()");
}
}
onResume和onPause糟港、onCreate不同的是攀操,它會(huì)嘗試調(diào)用一下onRestart。
android.app.Activity#performRestart:
final void performRestart() {
mFragments.noteStateNotSaved();
//很顯然這里是false秸抚,不會(huì)走進(jìn)去速和。只有當(dāng)退出Activity的時(shí)候才是true,才會(huì)調(diào)用onRestart聲明周期函數(shù)
if (mStopped) {
....
performStart();
}
}
這里也印證了啟動(dòng)Activity的聲明周期函數(shù)不包括onRestart剥汤。
android.app.Instrumentation#callActivityOnResume:
public void callActivityOnResume(Activity activity) {
activity.mResumed = true;
activity.onResume();
...
}
這里就是onResume的調(diào)用了气堕。
任務(wù)完成
我們知道周期函數(shù)是在looper里執(zhí)行的,跨進(jìn)程的調(diào)用實(shí)際上早已返回到了AMS中涩堤。當(dāng)Handler的LAUNCH_ACTIVITY消息發(fā)后缭受,這時(shí)AMS的主要任務(wù)就已經(jīng)完成了。而App進(jìn)程側(cè)完成了LAUNCH_ACTIVITY消息里的內(nèi)容后鹿驼,TargetActivity就算真正被啟動(dòng)了欲低。
總結(jié)
App進(jìn)程側(cè)的任務(wù)執(zhí)行都通過(guò)Looper來(lái)執(zhí)行的,不能一直阻塞著系統(tǒng)進(jìn)程畜晰。
- App進(jìn)程側(cè)記錄了構(gòu)造ActivityClientRecord砾莱,并且通過(guò)android.app.Activity#mToken映射好,存下來(lái)凄鼻,以備以后使用腊瑟。
- 調(diào)用了onCreate面哼、onStart
- 調(diào)用onResume。調(diào)用前檢查了是否需要調(diào)用onRestart扫步,發(fā)現(xiàn)不用調(diào)用魔策。