本文将分析activity的启动流程,把握主流程和一些疑难点及回调的触发时机。
该部分内容较长,会梳理流程并分析部分重点函数,读者可选择阅读,也可直接跳至总结部分
无论何种形式的startActivity,最终都会调用到startActivityForResult,该函数有三个参数需要理解一下:
intent即将要启动的目标intent
requestCode如果该值>0则该值将会在下一个activity启动后的onActivityResult返回获得
bundle可为null为配置参数。
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
if (mParent == null) {//没有parent的情况
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
// 这里用来作为下一个activity的返回标记
mStartedActivity = true;
}
final View decor = mWindow != null ? mWindow.peekDecorView() : null;
if (decor != null) {
decor.cancelPendingInputEvents();//用来取消输入事件传递,内部主要取消了onclick和longPress的回调
}
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {//有parent的情况,需要遍历子activity
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
mParent.startActivityFromChild(this, intent, requestCode);
}
}
if (options != null && !isTopOfTask()) {//大部分情况不用考虑
mActivityTransitionState.startExitOutTransition(this, options);
}
}
通过上述代码,我们不难看出,启动activity主要分为两个分支,判断条件就是mParent是否为null,那么mParent到底是什么,何时赋值的呢?我为读者梳理了activity源码并找出了这个对象的来由,首先在activity创建后回调onCreate前会先触发attach这个方法,该方法会给mParent赋值
该方法是在ActivityThread里performLaunchActivity调用
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.voiceInteractor);
再继续跟踪会发现LocalActivityManager的moveToState是调用源头
r.activity = mActivityThread.startActivityNow(
mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance);
而LocalActivityManager的mParent是在构造时传入的,创建LocalActivityManager的是AcivityGroup;
public LocalActivityManager(Activity parent, boolean singleMode) {
mActivityThread = ActivityThread.currentActivityThread();
mParent = parent;
mSingleMode = singleMode;
}
public ActivityGroup(boolean singleActivityMode) {
mLocalActivityManager = new LocalActivityManager(this, singleActivityMode);
}
到这里我们就可以得出结论了,ActivityGroup创建后在其内部启动activity才会有mParent,其他情况mParent是null,而ActivityGroup是解决一个界面内可以存在多个activity问题提供的方案,后来已经被Fragment取代。
所以回到我们startActivityForResult的分析中,mParent在没有ActivityGroup的情况下都是null,我们基本不用考虑,我们接着分析不存在mParent的流程;
execStartActivity
(ActivityManagerService)startActivity
startActivityAsUser
(ActivityStackSupervisor)startActivityMayWait
startActivityLocked
startActivityUncheckedLocked
startActivityMayWait:这个函数先会有Binder的一系列UID/PID检查,检测当前包名和进程名,以及是否已存在重量级操作;
startActivityLocked:这里简言之就是各种check,最后一步以前先启动PendingActivity;
startActivityUncheckedLocked:首先确定是否需要出现在后台任务栈,然后通过传入的intent确定启动模式,当代码intent和manifest冲突时,manifest优先,以下是源码解释
// We have a conflict between the Intent and the Activity manifest, manifest wins.
根据确定的flag及caller的属性来决定是否要开启新的task,和是否要清除已存在activity上面的activity,或者栈顶已经是将启动的activity,这里将会分为两种情况:注意该方法执行完就将返回值返回了,将执行startActivityAsUser后面的函数检查执行结果:
public static void checkStartActivityResult(int res, Object intent) {
if (res >= ActivityManager.START_SUCCESS) {
return;
}
switch (res) {
case ActivityManager.START_INTENT_NOT_RESOLVED:
case ActivityManager.START_CLASS_NOT_FOUND:
if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
throw new ActivityNotFoundException(
"Unable to find explicit activity class "
+ ((Intent)intent).getComponent().toShortString()
+ "; have you declared this activity in your AndroidManifest.xml?");
throw new ActivityNotFoundException(
"No Activity found to handle " + intent);
case ActivityManager.START_PERMISSION_DENIED:
throw new SecurityException("Not allowed to start activity "
+ intent);
case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
throw new AndroidRuntimeException(
"FORWARD_RESULT_FLAG used while also requesting a result");
case ActivityManager.START_NOT_ACTIVITY:
throw new IllegalArgumentException(
"PendingIntent is not an activity");
case ActivityManager.START_NOT_VOICE_COMPATIBLE:
throw new SecurityException(
"Starting under voice control not allowed for: " + intent);
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
}
}
在这里我们能看见一些常见的错误,如ActivityNotFoundException have you declared this activity in your AndroidManifest.xml?这就是没有在manifest里定义activity的错误;
standard启动模式,将执行startActivityLocked
targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
该方法会将将启动的activity任务栈移动到顶部即前台栈,当将启动的activity和当前activity不在同一进程或者要启动新的栈时,会启动一个空白的preview window,如果是第一个topActivity就不需要动画,最后将执行resume操作;
(ActivityStackSupervisor)resumeTopActivitiesLocked
(ActivityStack)resumeTopActivityLocked
(ActivityStack)resumeTopActivityInnerLocked
(ActivityThread)handlePauseActivity
(ActivityThread)performPauseActivity
(ActivityStackSupervisor)startSpecificActivityLocked(next, true, true)
(ActivityThread)scheduleLaunchActivity
(ActivityThread)handleLaunchActivity
(ActivityThread)performLaunchActivity
(ActivityThread)handleResumeActivity
resumeTopActivitiesLocked:这里有一个注意点,该函数的尾部会执行两次;
resumeTopActivityLocked,第一次是目标栈activity即将要启动的,第二次是前台栈activity,这里也就解释了为什么A使用singleInstance模式,启动其他Bactivity之后再启动回来,B先destroy后又重新create的问题,handleLaunchActivity函数会进一步解释,这个activity如果是非关闭的但不是前台的activity需要onPause;
resumeTopActivityInnerLocked:会去找当前栈顶的activity,如果没有则会启动桌面launcher,检查所有的paused activity有没有完成,先将当前activity执行pause操作再resume目标activity,注意点从这个函数的源码也可以看出onActivityResult和onNewIntent的触发都先于onResume;
performPauseActivity:这里有一个注意点,如果不是finishActivity且targetSdk版本低于3.1才会触发onSaveInstance,我们从这个函数里也可以发现onSaveInstance触发先于onPause;
startSpecificActivityLocked:这个函数后两个参数表示是否需要resume和checkConfig后面启动流程会有用到;
handleLaunchActivity:这里我们也可以看出onConfigurationChange检测和触发要先于activity创建;
performLaunchActivity:用ClassLoader的newInstance来创建activity实例,执行makeApplication创建application和应用context触发applicaiton的onCreate,然后为activity创建context,调用activity.attach,为activity设置主题,触发onCreate,触发onRestoreInstanceState;
handleResumeActivity:首先关闭强制GC,这个GC是不能小于5S间隔的,而且会阻塞MainLooper,然后会按符合的条件依次执行如下代码:
if (r.pendingIntents != null) {
deliverNewIntents(r, r.pendingIntents);//这里面会执行onNewIntent
r.pendingIntents = null;
}
if (r.pendingResults != null) {
deliverResults(r, r.pendingResults);/这里面会执行onActivityResult并传递给fragment
r.pendingResults = null;
}
r.activity.performResume();//后面详述
从以上代码我们可以看出,如果有pendingIntent,且有pendingResults会先执行onNewIntent再onActivityResult,接着我们分析一下performResume方法:
final void performResume() {
performRestart();//处理restart和start流程
···省略
mCalled = false;
mInstrumentation.callActivityOnResume(this);//回调onResume
···省略
mFragments.dispatchResume();//给fragment传递onResume
···省略
onPostResume();//回调window的onActive
···省略
}
final void performRestart() {
···省略
if (mStopped) {//这个标记位在onStop回调会置为true
···省略
mInstrumentation.callActivityOnRestart(this);//回调onReStart
···省略
performStart();//处理onStart流程
}
}
final void performStart() {
···省略
mInstrumentation.callActivityOnStart(this);//回调onStart
···省略
mFragments.dispatchStart();//给fragment传递onStart
···省略
mActivityTransitionState.enterReady(this);//后面详述
}
public void enterReady(Activity activity) {
···省略
if (mEnterActivityOptions.isReturning()) {
restoreExitedViews();//执行decorView的requesLayout
activity.getWindow().getDecorView().setVisibility(View.VISIBLE);//使decorView可见
}
···省略
}
如上,为resume流程的主要几个步骤,另外如果activity不实现super.onResume(其他生命周期回调相同)的话会收到一个SuperNotCalledException。
通过上面代码流程分析我总结了以下关键点:
之后将会执行deliverNewIntentLocked
if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
|| launchSingleInstance || launchSingleTask) {
ActivityRecord top = intentActivity.task.performClearTaskLocked(r, launchFlags);
if (top != null) {
if (top.frontOfTask) {
top.task.setIntent(r);
}
ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
r, top.task);
top.deliverNewIntentLocked(callingUid, r.intent);
}
······//省略
} else if (r.realActivity.equals(intentActivity.task.realActivity)) {
if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
&& intentActivity.realActivity.equals(r.realActivity)) {
ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
intentActivity.task);
if (intentActivity.frontOfTask) {
intentActivity.task.setIntent(r);
}
intentActivity.deliverNewIntentLocked(callingUid, r.intent);
}
onNewIntent执行完之后,此时会将栈顶的activity进行resume操作resumeTopActivityLocked这里会依次执行onReStart、onStart、onResume流程和之前正常启动类似,不做赘述;