写这篇文章的时候刚好是2020年春节,全民抗击肺炎病毒,今年不能出门拜年,只能在家老实呆着,也没啥事来作,我就寻思着写点东西,但愿能帮助一点人,以为不错的话,能够给个赞哦,哈哈哈~java
分析源码以前呢,咱先本身先思考几个问题,分析完成后,看能不能解决掉~app
启动模式相关源码都在ActivityStarter.java文件的startActivityUnchecked这个方法, 咱们拆解这个函数来分析一下:( Android 9.0 代码为例 )ide
注意下两个很重要的属性 mLaunchFlags,mLaunchMode,后面的源码分析也主要围绕着两个属性在讨论函数
mLaunchFlags 包含启动的flag,好比FLAG_ACTIVITY_NEW_TASK,FLAG_ACTIVITY_CLEAR_TASK等,做用是规定了如何去启动一个Activity。源码分析
mLaunchMode 表示启动模式,好比LAUNCH_SINGLE_INSTANCE,LAUNCH_SINGLE_TASK等。post
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity) {
// 初始化 mLaunchFlags mLaunchMode
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);
// 一.计算 mLaunchFlags
computeLaunchingTaskFlags();
//赋值 mSourceTask
computeSourceStack();
mIntent.setFlags(mLaunchFlags);
... ... ...
复制代码
看 computeLaunchingTaskFlags 方法this
private void computeLaunchingTaskFlags() {
... ... ...
// mSourceRecod 指的是 启动者,(注意区别于 被启动者 mStartActivity) mSourceRecord为null,表示咱们不是从一个Activity来启动的
// 多是从 一个Service 或者 ApplicationContext 来的
if (mSourceRecord == null) {
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
//mInTask mSourceRecord 都为null, 表示 不是从一个Activity 去启动另一个Activity,因此无论什么
//都加上 FLAG_ACTIVITY_NEW_TASK
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
} else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
// 若是 启动者 本身是 SINGLE_INSTANCE , 那么无论被启动的Activity是什么模式,mLaunchFlags 都加上 FLAG_ACTIVITY_NEW_TASK,
// 这个新 Activity 须要运行在 本身的 栈内
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
} else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
//若是launchMode是 SINGLE_INSTANCE 或者 SINGLE_TASK; mLaunchFlags 添加 FLAG_ACTIVITY_NEW_TASK
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
}
复制代码
注意图中有3个地方为mLaunchFlags添加了FLAG_ACTIVITY_NEW_TASK spa
这一部分仍是startActivityUnchecked方法的一个片断,紧接着第一部分的源码3d
//仍是在 startActivityUnchecked 里面
... ... ...
// 1. 为SINGLE_INSTANCE查找能够复用的Activity
// 2. 为 只有FLAG_ACTIVITY_NEW_TASK而且没有MULTI_TASK的
// 3. SINGLE_TASK 查找能够添加的栈
ActivityRecord reusedActivity = getReusableIntentActivity();
... ... ...
复制代码
咱们顺便也跳出startActivityUnchecked方法,去看一看getResuableIntentActivity方法。code
private ActivityRecord getReusableIntentActivity() {
//putIntoExistingTask为true的条件
//(1)当启动模式为SingleInstance;
//(2)当启动模式为SingleTask;
//(3)使用了Intent.FLAG_ACTIVITY_NEW_TASK标签,而且没有使用FLAG_ACTIVITY_MULTIPLE_TASK标签
boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
(mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK);
putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
ActivityRecord intentActivity = null;
if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
... ... ...
} else if (putIntoExistingTask) { //putIntoExistingTask为true时的策略
if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) {
// SINGLE_INSTANCE 模式下去寻找,这里目的是findActivityRecord
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
mStartActivity.isActivityTypeHome());
} else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
... ...
} else {
//这里要区别于singleInstance调用的方法!!!这里目的是findTaskRecord
// Otherwise find the best task to put the activity in.
intentActivity = mSupervisor.findTaskLocked(mStartActivity, mPreferredDisplayId);
}
}
return intentActivity;
}
复制代码
下图表示的是三种状况下putIntoExistingTask为true
mLaunchMode为SingleInstance时,走mSupervisor.findActivityLocked;
其余状况下,好比咱们的mStartActivity是一个standard模式的Activity,且只加上了FLAG_ACTIVITY_NEW_TASK的flag,会走mSupervisor.findTaskLocked
这里咱们能够隐约猜出来出来,被启动者为SinglgeInstance的状况下,咱们是寻找相等的ActivityRecord;而其余状况下,咱们找的是一个最合适的栈(从注释也能够看出来)。实际上咱们猜的很对,对于SingleInstance的状况,源码上也是遍历查找相同的ActivityRecord。可是对于其余状况呢?咱们先思考一个问题,什么叫最合适的栈?它须要知足什么样的条件?
先说一个预备的知识点。咱们的AMS如何管理咱们众多的Activity的?
从mSupervisor.findTaskLocked进入,咱们最后追踪到ActivityStack.java
void findTaskLocked(ActivityRecord target, FindTaskResult result) {
... ... ...
// 注意看这里是倒序遍历 mTaskHistory
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
... ... ...
} else if (!isDocument && !taskIsDocument
&& result.r == null && task.rootAffinity != null) {
//检查 是否是 相同的 taskAffinity
if (task.rootAffinity.equals(target.taskAffinity)) {
//当咱们找到taskAffinity符合的栈以后,并无立马break,而是继续去寻找,说明task的index越小,表示更适合
result.r = r;
result.matchedByRootAffinity = true;
}
} else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
}
}
复制代码
最合适的栈 知足两个条件
1.Activity的taskAffinity和咱们的task的rootAffinity相等
2.不一样的task的rootAffinity多是相等的,倒序遍历找到index最小的,也是最合适的
咱们接着分析startActivityUnchecked代码
// 三. 利用能够 复用的Activity 或者 复用栈
if (reusedActivity != null) {
... ... ...
// 若是是 SINGLE_INSTANCE 或者 SINGLE_TASK 或者 含有 FLAG_ACTIVITY_CLEAR_TOP 标识
//咱们能够判断出来 SINGLE_INSTANCE 或者 SINGLE_TASK 含有 FLAG_ACTIVITY_CLEAR_TOP 的效果
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
//拿 reuseActivity 的栈
final TaskRecord task = reusedActivity.getTask();
// 好比 singleTask 移除要启动的Activity以前的全部Activity
final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
mLaunchFlags);
if (reusedActivity.getTask() == null) {
reusedActivity.setTask(task);
}
if (top != null) {
if (top.frontOfTask) {
// Activity aliases may mean we use different intents for the top activity,
// so make sure the task now has the identity of the new intent.
top.getTask().setIntent(mStartActivity);
}
//这里是 SingleInstance 或者 SingleTask ,会执行onNewIntent
deliverNewIntent(top);
}
}
... ... ...
//启动者和被启动者是同一个
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and the client said not to do anything
// if that is the case, so this is it! And for paranoia, make sure we have
// correctly resumed the top activity.
resumeTargetStackIfNeeded();
return START_RETURN_INTENT_TO_CALLER;
}
if (reusedActivity != null) {
//这里会去判断几种状况 singleTask singleInstance 和 singleTop
setTaskFromIntentActivity(reusedActivity);
if (!mAddingToTask && mReuseTask == null) {
//singleInstance singleTask 都会走这里
//1.好比要启动的Activity是singleTask,且恰好在reusedActivity的栈内
//2.或者一个singleInstance模式的Activity再次被启动
resumeTargetStackIfNeeded();
if (outActivity != null && outActivity.length > 0) {
outActivity[0] = reusedActivity;
}
return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;
}
}
}
复制代码
继续来看一下setTaskFromIntentActivity这个方法
private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
//若是是 FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TASK
final TaskRecord task = intentActivity.getTask();
//清空task
task.performClearTaskLocked();
mReuseTask = task;
mReuseTask.setIntent(mStartActivity);
} else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
//若是是 singleInstance 或者 singleTask 走这里,清空栈内要启动的Activity以前的全部Activity们。
ActivityRecord top = intentActivity.getTask().performClearTaskLocked(mStartActivity,
mLaunchFlags);
//若是top == null 继续走,不为null,就结束了这个方法
if (top == null) {
... ... ...
}
} else if (mStartActivity.realActivity.equals(intentActivity.getTask().realActivity)) {
// 判断是不是 singleTop 模式
// 这种状况如何复现? singleTop + FLAG_ACTIVITY_NEW_TASK + taskAffinity。
// FLAG_ACTIVITY_NEW_TASK + taskAffinity去指定一个特定存在的栈,且栈顶是咱们要启动的singleTop模式的activity
if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| LAUNCH_SINGLE_TOP == mLaunchMode)
&& intentActivity.realActivity.equals(mStartActivity.realActivity)) {
if (intentActivity.frontOfTask) {
intentActivity.getTask().setIntent(mStartActivity);
}
deliverNewIntent(intentActivity);
} else if (!intentActivity.getTask().isSameIntentFilter(mStartActivity)) {
... ... ...
}
} else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
... ... ...
} else if (!intentActivity.getTask().rootWasReset) {
... ... ...
}
}
复制代码
前提是reusedActivity不为null,看两种典型状况:
1.若是是SingleTask或者是SingleInstance模式的Activity,则执行performClearTaskLocked方法,把要启动的Activity以前的全部Activity都清除掉。
2.reusedActivity的启动模式刚好是SingleTop,且也是咱们要启动的Activity,执行 deliverNewIntent。
上述的两种状况可以知足下面的if判断 !mAddingToTask && mReuseTask == null ,而后return结束。
思考一个问题,状况1和2作例子来浮现一下?
继续看 startActivityUnchecked 后面的代码,这一部分是针对SingleTop模式的处理。
注意哦,以前咱们也遇到了SingleTop模式的处理,就在上面的setTaskFromIntentActivity方法里。这两个有什么区别呢?
区别在这里的SingleTop模式判断的栈是咱们当前展现的栈。而setTaskFromIntentActivity里的判断前提条件是在咱们的reusedActivity不为空的状况下,对reusedActivity进行的判断,reusedActivity可能并非当前的栈。
... ... ...
//下面这段英文解释的很好(singleTop模式),当咱们要启动的Actiivty刚好是当前栈顶的Activity,检查是否只须要被启动一次
// If the activity being launched is the same as the one currently at the top, then
// we need to check if it should only be launched once.
final ActivityStack topStack = mSupervisor.mFocusedStack;
final ActivityRecord topFocused = topStack.getTopActivity();
final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
final boolean dontStart = top != null && mStartActivity.resultTo == null
&& top.realActivity.equals(mStartActivity.realActivity)
&& top.userId == mStartActivity.userId
&& top.app != null && top.app.thread != null
&& ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK));
// SINGLE_TOP SINGLE_TASK,要启动的Activiy刚好在栈顶
// dontStart为true,表示不会去启动新的Activity,复用栈顶的Activity
if (dontStart) {
// For paranoia, make sure we have correctly resumed the top activity.
topStack.mLastPausedActivity = null;
if (mDoResume) {
// resume Activity
mSupervisor.resumeFocusedStackTopActivityLocked();
}
ActivityOptions.abort(mOptions);
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and the client said not to do
// anything if that is the case, so this is it!
return START_RETURN_INTENT_TO_CALLER;
}
deliverNewIntent(top);
// Don't use mStartActivity.task to show the toast. We're not starting a new activity
// but reusing 'top'. Fields in mStartActivity may not be fully initialized.
mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredWindowingMode,
preferredLaunchDisplayId, topStack);
return START_DELIVERED_TO_TOP;
}
复制代码
这部分的代码主要处理SingleTop模式的Activity,要启动的Activity是SingleTop模式,且也刚好在当前栈的顶部,执行deliverNewIntent。
思考一个小问题,启动一个SingleTop模式的Activity,而后再次启动一次它,它的生命周期如何变化呢?
答案是 onCreate -> onStart -> onResume -> onPause -> onNewIntent -> onResume。
继续分析startActivityUnChecked方法的最后一部分,这部分主要是关于栈是否须要新建。
... ... ...
//必要条件是有FLAG_ACTIVITY_NEW_TASK
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
//要创建新栈或者使用已经存在的栈,FLAG_ACTIVITY_NEW_TASK是必要条件
newTask = true;
result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
} else if (mSourceRecord != null) {
//把被启动的mStartActivity放在启动者mSourceRecord所在的栈上
result = setTaskFromSourceRecord();
}
... ... ...
复制代码
setTaskFromReuseOrCreateNewTask 方法
private int setTaskFromReuseOrCreateNewTask( TaskRecord taskToAffiliate, ActivityStack topStack) {
mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions);
if (mReuseTask == null) {
//新建一个栈
final TaskRecord task = mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity, mSourceRecord,
mOptions);
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
updateBounds(mStartActivity.getTask(), mLaunchParams.mBounds);
} else {
//用旧栈
addOrReparentStartingActivity(mReuseTask, "setTaskFromReuseOrCreateNewTask");
}
... ... ...
复制代码
咱们能够看出,若是须要咱们去新建一个栈或者把咱们要启动的Activity放在已经存在某个栈中,FLAG_ACTIVITY_NEW_TASK是必要条件。
对于第二部分的描述我用一个图来总结一下。
咱们先总结一下几个重要的结论:
FLAG_ACTIVITY_NEW_TASK是新建栈或者复用栈的必要条件。SingleTask,SingleInstance会为mLaunchFlags自动添加FLAG_ACTIVITY_NEW_TASK。也就是说他们都有存在不使用当前栈的可能。SingleInstance是很好理解的,SingleTask须要注意下,关于SingleTask我会详细说明,不用担忧。
新建栈或者复用已经存在栈的充要条件是什么?
(1) FLAG_ACTIVITY_NEW_TASK + taskAffinity(taskAffinity必须与当前显示的栈的rootAffinity不相同,taskAffinity默认是包名)
(2) FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_MULTIPLE_TASK 这是一定会新建一个栈的
SingleTask能够理解成FLAG_ACTIVITY_TASK + CLEAR_TOP + (taskAffinity == 该应用包名)
SingleInstance比较特殊,自己FLAG_ACTIVITY_NEW_TASK,特殊的地方其一在于若是启动过了,会去遍历找相等的Activity,查找过程不同。而不像SingleTask是去找合适存放的栈,根据taskAffinity来查找。其二在于SingleInstance一个栈只能存放一个Activity,能作到这个的缘由是咱们在根据taskAffinity找到合适的栈的时候,若是发现是SingleInstance模式Activity的栈,直接忽略。
到这里也算是完结了,咱们回过头来思考一下最开始提出的几个问题。
若两个应用A和B,A中有两个Activity,A1和A2,B中有一个Activity B1,这三个Activity都是SingleTask模式,那么启动顺序是A1 -> B1 -> A2,返回的其实是A1。由于SingleTask模式自己含有FLAG_ACTIVITY_NEW_TASK,这里因为taskAffinity也和当前展现的栈不相同,因此会去找"合适的"栈放入。
接着前面问题,若是A2是Standard模式 + FlAG_ACTIVITY_NEW_TASK呢? 会回到A1,由于A2和A1在一个栈,相似第一种状况。
FLAG_ACTIVITY_NEW_TASK 有什么用?taskAffinity又是啥?这个问题能够看上面的小结。