一直想抽空针对AMS进行源码分析,无奈一方面因为很忙,另外AMS很复杂,涉及的知识点也比较多,今天利用五一假期对AMS的一个方面,Activity的启动模式进行源码分析,这里面包括了ActivityRecord,TaskRecord,ActivityStack等概念,写这篇博客之前,我也百度了不少朋友的启动模式介绍和分析,有些讲的不清楚,少数从源码角度分析了,但是都看的非常麻烦,很难理解,我也一直在想,如何更好地阅读Android源码或者写关于源码分析的博客,我想了好久,目前个人觉得,写好源码博客,千万不能贴几大段源码上去,然后加点注释,这个效果很不好,一是很难有调理针对性的看,另外读者读起来也非常费劲。
本篇针对启动模式提了几个问题,一定要有针对性的问题去阅读源码,这样才能更加深刻理解其中的机制,本篇关于启动模式的几个问题如下:
1、如果被启动的Activity的模式是SingleTop,会在栈内重新创建该实例吗?如果不会,是什么情形,会又是什么情形?
2、如果被启动的Activity的模式是SingleTask,会重新创建栈吗?默认情况会还是不会?不会重新创建栈的话,会如何调用?如果会重新创建栈,又是在什么样的情形?
3、singleInstance的启动模式如何做到栈内唯一?
4、如果startActivity的intent设置了FLAG_ACTIVITY_NEW_TASK,一定会重新创栈吗?
5、如果singleTop的模式,设置了taskAffinity不一致,会重新创栈吗?如果要重新创建栈,要设置什么?
请读者也阅读下面源码之前,也思考一下这几个问题。
好,下面进行源码分析模式,Activity的启动模式相关逻辑的入口在ActivityStarter.java类中的 startActivityUnchecked方法
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);
computeLaunchingTaskFlags();
computeSourceStack();
mIntent.setFlags(mLaunchFlags);
mReusedActivity = getReusableIntentActivity();
final int preferredLaunchStackId =
(mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
if (mReusedActivity != null) {
if (mSupervisor.isLockTaskModeViolation(mReusedActivity.task,
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
mSupervisor.showLockTaskToast();
Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
if (mStartActivity.task == null) {
mStartActivity.task = mReusedActivity.task;
}
if (mReusedActivity.task.intent == null) {
// This task was started because of movement of the activity based on affinity...
// Now that we are actually launching it, we can assign the base intent.
mReusedActivity.task.setIntent(mStartActivity);
}
// This code path leads to delivering a new intent, we want to make sure we schedule it
// as the first operation, in case the activity will be resumed as a result of later
// operations.
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| mLaunchSingleInstance || mLaunchSingleTask) {
// In this situation we want to remove all activities from the task up to the one
// being started. In most cases this means we are resetting the task to its initial
// state.
final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
mStartActivity, mLaunchFlags);
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.task.setIntent(mStartActivity);
}
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
}
}
sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);
mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);
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;
}
setTaskFromIntentActivity(mReusedActivity);
if (!mAddingToTask && mReuseTask == null) {
// We didn't do anything... but it was needed (a.k.a., client don't use that
// intent!) And for paranoia, make sure we have correctly resumed the top activity.
resumeTargetStackIfNeeded();
return START_TASK_TO_FRONT;
}
}
if (mStartActivity.packageName == null) {
if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
mStartActivity.resultTo.task.stack.sendActivityResultLocked(
-1, mStartActivity.resultTo, mStartActivity.resultWho,
mStartActivity.requestCode, RESULT_CANCELED, null);
}
ActivityOptions.abort(mOptions);
return START_CLASS_NOT_FOUND;
}
// 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 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
|| mLaunchSingleTop || mLaunchSingleTask);
if (dontStart) {
ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
// For paranoia, make sure we have correctly resumed the top activity.
topStack.mLastPausedActivity = null;
if (mDoResume) {
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;
}
top.deliverNewIntentLocked(
mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
// 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.task, preferredLaunchStackId, topStack.mStackId);
return START_DELIVERED_TO_TOP;
}
boolean newTask = false;
final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.task : null;
// Should this be considered a new task?
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
setTaskFromReuseOrCreateNewTask(taskToAffiliate);
if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
if (!mMovedOtherTask) {
// If stack id is specified in activity options, usually it means that activity is
// launched not from currently focused stack (e.g. from SysUI or from shell) - in
// that case we check the target stack.
updateTaskReturnToType(mStartActivity.task, mLaunchFlags,
preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
}
} else if (mSourceRecord != null) {
if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
final int result = setTaskFromSourceRecord();
if (result != START_SUCCESS) {
return result;
}
} else if (mInTask != null) {
// The caller is asking that the new activity be started in an explicit
// task it has provided to us.
if (mSupervisor.isLockTaskModeViolation(mInTask)) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
final int result = setTaskFromInTask();
if (result != START_SUCCESS) {
return result;
}
} else {
// This not being started from an existing activity, and not part of a new task...
// just put it in the top task, though these days this case should never happen.
setTaskToCurrentTopOrCreateNewTask();
}
}
mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
return START_SUCCESS;
}
代码较多,我已经做了一部分删减,我先大概讲下方法,然后针对问题去分析
1、第5行 setInitialState 方法是设置变量初始化状态。
private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
boolean doResume, int startFlags, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
reset();// 重置状态
mStartActivity = r; // 被启动的Activity
mIntent = r.intent; //启动的intent
mSourceRecord = sourceRecord;//发起启动的Activity,比如A 启动B,A就是 sourceRecord
mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP; //是否是singleTop启动模式,下同
mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;
// 省略
2、第8行computeLaunchingTaskFlags 方法作用 是给不同的启动模式设置launchFlag,简言之,如果是singleTask或者singleInstance,就加上 FLAG_NEW_TASK的标签。
private void computeLaunchingTaskFlags() {
// If the caller is not coming from another activity, but has given us an explicit task into
// which they would like us to launch the new activity, then let's see about doing that.
if (mInTask == null) {
if (mSourceRecord == null) {
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
"Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
} else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
} else if (mLaunchSingleInstance || mLaunchSingleTask) {
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
}
}
3、第10行 computeSourceStack() 主要作用是赋值ActivityStack。
4、第14行 mReusedActivity = getReusableIntentActivity();判断是否要创建一个新的实例加入栈,如果需要mReusedActivity 不为空,如果不需要,为空。
/**
* Decide whether the new activity should be inserted into an existing task. Returns null
* if not or an ActivityRecord with the task into which the new activity should be added.
*/
private ActivityRecord getReusableIntentActivity() {
//标志位,如果为true,说明要放入已经存在的栈,可以看出,如果是设置了FLAG_ACTIVITY_NEW_TASK 而没有设置 FLAG_ACTIVITY_MULTIPLE_TASK,或者
设置了singleTask以及singleInstance
boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
(mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| mLaunchSingleInstance || mLaunchSingleTask;
// 重新检验
putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
ActivityRecord intentActivity = null
if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
intentActivity = task != null ? task.getTopActivity() : null;
} else if (putIntoExistingTask) {
if (mLaunchSingleInstance) {
//如果是 singleInstance,那么就找看看之前存在的该实例,找不到就为null
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);
}
else {
// Otherwise find the best task to put the activity in.
// 在栈中找出 符合要求的栈的topActivity,这里面也很复杂。
intentActivity = mSupervisor.findTaskLocked(mStartActivity);
}
}
return intentActivity;
}
/**
* Returns the top activity in any existing task matching the given Intent in the input result.
* Returns null if no such task is found.
*/
void findTaskLocked(ActivityRecord target, FindTaskResult result) {
Intent intent = target.intent;
ActivityInfo info = target.info;
ComponentName cls = intent.getComponent();
if (info.targetActivity != null) {
cls = new ComponentName(info.packageName, info.targetActivity);
}
final int userId = UserHandle.getUserId(info.applicationInfo.uid);
boolean isDocument = intent != null & intent.isDocument();
// If documentData is non-null then it must match the existing task data.
Uri documentData = isDocument ? intent.getData() : null;
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + this);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
final ActivityRecord r = task.getTopActivity();
if (r == null || r.finishing || r.userId != userId ||
r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
continue;
}
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
+ taskIntent.getComponent().flattenToShortString()
+ "/aff=" + r.task.rootAffinity + " to new cls="
+ intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
// TODO Refactor to remove duplications. Check if logic can be simplified.
if (taskIntent != null && taskIntent.getComponent() != null &&
taskIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
//dump();
if (DEBUG_TASKS) Slog.d(TAG_TASKS,
"For Intent " + intent + " bringing to top: " + r.intent);
result.r = r;
result.matchedByRootAffinity = false;
break;
} else if (affinityIntent != null && affinityIntent.getComponent() != null &&
affinityIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
//dump();
if (DEBUG_TASKS) Slog.d(TAG_TASKS,
"For Intent " + intent + " bringing to top: " + r.intent);
result.r = r;
result.matchedByRootAffinity = false;
break;
} else if (!isDocument && !taskIsDocument
&& result.r == null && task.canMatchRootAffinity()) {
if (task.rootAffinity.equals(target.taskAffinity)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
// It is possible for multiple tasks to have the same root affinity especially
// if they are in separate stacks. We save off this candidate, but keep looking
// to see if there is a better candidate.
result.r = r;
result.matchedByRootAffinity = true;
}
} else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
}
}
源码实在太多,我不想继续贴了,直接看问题说吧,最好自己也打开源码,对照起来读。
1、如果是singleTop的启动模式,computeLaunchingTaskFlags和它没有关系,这个方法没有针对这个模式设定flag,getReusableIntentActivity 得到的也是null,因为这个方法也不是主要针对这个模式(前提是启动的intent没有设置FLAG_ACTIVITY_NEW_TASK),
mReusedActivity 为null,我们看 final boolean dontStart = top != null && mStartActivity.resultTo == null 这一行之后,这里面就要分情况讨论了:
第一种情形:如果该Activity就是在栈顶,dontStart 为true,那么就调用其onNewIntent方法。
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
|| mLaunchSingleTop || mLaunchSingleTask);
if (dontStart) {
top.deliverNewIntentLocked(
mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
第二种情形:如果不在栈顶,那么 dontStart 为false,就会重新创建实例。
2、如果是singleTask模式,在第二个代码段,会将mLaunchFlags设置成FLAG_ACTIVITY_NEW_TASK模式,其效果等同于我们自己主动 加了这个flag,还是重点看下 getReusableIntentActivity方法,第三个代码段,
boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
(mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| mLaunchSingleInstance || mLaunchSingleTask;
这个里面 putIntoExistingTask 为true。
走到下面第二个分支 ,调用 findTaskLocked方法。
else if (putIntoExistingTask) {
if (mLaunchSingleInstance) {
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);
} else {
// Otherwise find the best task to put the activity in.
intentActivity = mSupervisor.findTaskLocked(mStartActivity);
}
}
findTaskLocked 贴出来的代码非常长,我概括下,如果我们被启动的Activity没有显式的配置不一致的 taskAffinity,那么 调用到该方法的这里。
else if (!isDocument && !taskIsDocument
&& result.r == null && task.canMatchRootAffinity()) {
if (task.rootAffinity.equals(target.taskAffinity)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
// It is possible for multiple tasks to have the same root affinity especially
// if they are in separate stacks. We save off this candidate, but keep looking
// to see if there is a better candidate.
result.r = r;
result.matchedByRootAffinity = true;
}
mReusedActivity 返回的是该栈中顶部的Activity,如果配置了不一样的taskAffinity,那么mReusedActivity就为null。
如果不为null,那么第一个代码段往下走,会走到这里。
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| mLaunchSingleInstance || mLaunchSingleTask) {
//清除 该Activity在栈中上方的所有Activity
final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
mStartActivity, mLaunchFlags);
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.task.setIntent(mStartActivity);
}
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
// 调用 onNewIntent方法
top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
}
}
如果singleTask是一样的taskAffinity,会清除 其上方的所有activity,也就不会重新创栈。
因为 此时mAddingToTask 即使为false,但是走到这一段代码:
因为此时的topActivity就是 该模式的Activity,又满足了 mLaunchSingleTask模式,return掉了。
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
|| mLaunchSingleTop || mLaunchSingleTask);
if (dontStart) {
ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
// For paranoia, make sure we have correctly resumed the top activity.
topStack.mLastPausedActivity = null;
if (mDoResume) {
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;
}
top.deliverNewIntentLocked(
mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
// 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.task, preferredLaunchStackId, topStack.mStackId);
return START_DELIVERED_TO_TOP;
}
如果是不一样的taskAffinity,那么 mReusedActivity为null,走下面的代码段:
boolean newTask = false;
final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.task : null;
// Should this be considered a new task?
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
setTaskFromReuseOrCreateNewTask(taskToAffiliate)
mAddingToTask 默认为false, 因为singelTask的启动flag被设置成了 FLAG_ACTIVITY_NEW_TASK,所以 newTask 为true,调用创建新栈的逻辑。
好了,关于第二个问题也解答二楼。
3、如果是singleIntance模式,如果栈中已经存在该实例了,那么mReusedActivity不为空,这里有个注意点,系统针对这种模式,进行了单独处理,如果是 singleIntance,就去找该实例,然后赋值给 mReusedActivity,如果是其他模式,只是去找相同栈中的topActivity就可以了,一定要注意这一点,因为 singleIntance一定是栈中唯一的一个实例存在。
代码如下
if (mLaunchSingleInstance) {
// There can be one and only one instance of single instance activity in the
// history, and it is always in its own unique task, so we do a special search.
**intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);**
} else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
// For the launch adjacent case we only want to put the activity in an existing
// task if the activity already exists in the history.
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
!mLaunchSingleTask);
} else {
// Otherwise find the best task to put the activity in.
intentActivity = mSupervisor.findTaskLocked(mStartActivity);
}
如果 mReusedActivity不为空,说明之前启动过,会调用和singletask一样的流程,清除上面的activity(假设栈中其上方有其他实例)。
如果 mReusedActivity为空,还是会走到下面这个分支。
// Should this be considered a new task?
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
setTaskFromReuseOrCreateNewTask(taskToAffiliate);
if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
if (!mMovedOtherTask) {
// If stack id is specified in activity options, usually it means that activity is
// launched not from currently focused stack (e.g. from SysUI or from shell) - in
// that case we check the target stack.
updateTaskReturnToType(mStartActivity.task, mLaunchFlags,
preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
}
4、如果仅仅设置了FLAG_ACTIVITY_NEW_TASK,那么并不会重新创建新栈,因为代码中还多了这个条件判断:
boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
(mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| mLaunchSingleInstance || mLaunchSingleTask;
可以看出来,即使 设置了这个如果缺少了 FLAG_ACTIVITY_MULTIPLE_TASK,
putIntoExistingTask 还是为true,那么还是会在原有的栈。除非加上 FLAG_ACTIVITY_MULTIPLE_TASK 的flag。
5、如果singleTop的模式设置了不同的taskAffinity,那么mReusedActivity就为null,导致mAddingToTask为false,如果加上 启动intent的flag为 FLAG_ACTIVITY_NEW_TASK的话,也是可以重新创建新栈的。
总结:
在不考虑主动设置启动的intent flag情况下:
1、standmode标准模式,启动一个新建一个实例,放入栈中。
2、singleTop,如果是栈顶部,复用,调用onNewIntent,如果不是,重新创建,放入栈顶。
3、singleTask,如果想要的栈已经存在,如果实例也在栈中存在,清除上方实例,如果不存在,创建该实例,如果想要的栈不存在,重新创建栈。
4、singleInstance,无论什么时候,都是栈内唯一,甚至全局唯一。
最后说实话,Android启动模式源码这一块写的真的非常非常的乱,是我读过相对很乱的代码,严重吐槽这一点。