在分析点击android桌面app图标启动应用程序的过程这篇文章中,第三步和第十二步简单提到了启动activity的启动标识FLAG_ACTIVITY_NEW_TASK以及task的概念.
这里就来讲解一下task,activity启动模式,启动标识相关知识.
参考https://developer.android.com/guide/components/tasks-and-back-stack.html#ManagingTasks.
task(任务)的作用是确保Activity启动和退出的顺序.activity必须在一个任务中启动,一个任务中可以有个多个activity.当然系统中可以有多个任务.这些任务中的activity都是有序的.任务是栈的结构,所以activity启动和退出遵循"后进先出".
既然activity必须在一个任务中启动,那么决定activity在哪个任务中启动(这里有可能是在现有的任务中也有可能创建一个新任务)则由activity启动模式和启动标识两者共同决定.
activity启动模式是在清单配置文件中声明Activity时使用
元素的 launchMode
属性指定 .这里可以看作是该activity本身自己希望在哪个任务中启动
启动标识是指调用 startActivity()
时,可以在 Intent
中加入一个标志,用于声明新 目标Activity 在哪个任务中启动.这里可以看作是调用者希望目标activity如何启动.
在分析点击android桌面app图标启动应用程序的过程一文中在launcher应用程序(调用者)在启动目标actvitity的intent中添加了FLAG_ACTIVITY_NEW_TASK标识,是希望创建一个新的任务,在该新的任务中启动该activity.此时目标activity的launchMode值是
"standard"
(默认模式)所以:
①
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
int launchFlags = intent.getFlags();
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
if (sourceRecord == null) {
// This activity is not being started from another... in this
// case we -always- start a new task.
if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
....
}
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
...
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
....
}
...
boolean addingToTask = false;
boolean movedHome = false;
TaskRecord reuseTask = null;
if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// If bring to front is requested, and no result is requested, and
// we can find a task that was started with this same
// component, then instead of launching bring that one to the front.
if (r.resultTo == null) {
// See if there is a task to bring to the front. If this is
// a SINGLE_INSTANCE activity, there can be one and only one
// instance of it in the history, and it is always in its own
// unique task, so we do a special search.
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)
: findActivityLocked(intent, r.info);
if (taskTop != null) {
....
}
}
......
if (r.packageName != null) {
// 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.
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null) {
...
}
}
} else {
....
}
boolean newTask = false;
boolean keepCurTransition = false;
// Should this be considered a new task?
if (r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
if (reuseTask == null) {
// todo: should do better management of integers.
mService.mCurTask++;
if (mService.mCurTask <= 0) {
mService.mCurTask = 1;
}
r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);//创建一个新的任务,在该任务中启动目标activity
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new task " + r.task);
} else {
....
}
newTask = true;
...
} else if (sourceRecord != null) {
...
} else {
....
}
.....
}
一:"standard"
(默认模式).系统在启动 Activity 的任务中创建 Activity 的新实例并向其传送 Intent。Activity 可以多次实例化,而每个实例均可属于不同的任务,并且一个任务可以拥有多个实例.
如果目标activity的启动模式是"standard",启动该目标activity时没有添加启动标识(intent没有添加相关flag),那么结果就是在当前的任务中启动该目标activity.比如a应用程序的A activity启动b应用程序中 B activity,这里假设A B 两个activity的启动模式都是standard.那么结果就会在A activity所在任务中启动B activity.看一下源代码:
②
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
...
if (sourceRecord == null) {
...
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
....
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
....
}
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
....
}
boolean addingToTask = false;
boolean movedHome = false;
TaskRecord reuseTask = null;
if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
....
}
....
if (r.packageName != null) {
// 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.
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null) {
if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
....
}
}
}
} else {
...
}
boolean newTask = false;
boolean keepCurTransition = false;
// Should this be considered a new task?
if (r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
....
} else if (sourceRecord != null) {
if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
....
} else if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
....
}
// An existing activity is starting this new activity, so we want
// to keep the new one in the same task as the one that is starting
// it.
r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);//目标activity和调用者是在同一个任务中
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in existing task " + r.task);
} else {
..
}
....
}
当启动该目标activity时没有添加启动标识(intent没有添加相关flag),但是A activity的启动模式是"singleInstance" B activity的启动模式依然是"standard",那么结果就会在B activity会在新的任务中启动.看一下源代码:
③
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
...
int launchFlags = intent.getFlags();
.....
if (sourceRecord == null) {
// This activity is not being started from another... in this
// case we -always- start a new task.
if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
....
}
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {//A activity的启动模式是single instance
// The original activity who is starting us is running as a single
// instance... this new activity it is starting must go on its
// own task.
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;//这里就给启动标识赋值成了 new task
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
......
}
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
...
}
boolean addingToTask = false;
boolean movedHome = false;
TaskRecord reuseTask = null;
if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// If bring to front is requested, and no result is requested, and
// we can find a task that was started with this same
// component, then instead of launching bring that one to the front.
if (r.resultTo == null) {
// See if there is a task to bring to the front. If this is
// a SINGLE_INSTANCE activity, there can be one and only one
// instance of it in the history, and it is always in its own
// unique task, so we do a special search.
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)
: findActivityLocked(intent, r.info);
if (taskTop != null) {
....
}
}
}
//String uri = r.intent.toURI();
//Intent intent2 = new Intent(uri);
//Slog.i(TAG, "Given intent: " + r.intent);
//Slog.i(TAG, "URI is: " + uri);
//Slog.i(TAG, "To intent: " + intent2);
if (r.packageName != null) {
// 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.
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null) {
if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
....
}
}
} else {
....
}
boolean newTask = false;
boolean keepCurTransition = false;
// Should this be considered a new task?
if (r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
if (reuseTask == null) {
// todo: should do better management of integers.
mService.mCurTask++;
if (mService.mCurTask <= 0) {
mService.mCurTask = 1;
}
r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);//在新的任务中启动 B activity
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new task " + r.task);
} else {
...
}
newTask = true;
if (!movedHome) {
moveHomeToFrontFromLaunchLocked(launchFlags);
}
} else if (sourceRecord != null) {
...
} else {
...
}
.....
}
当然还有很多种情况,这里就不一一列举了,通过源码就很容易知道
二:"singleTop"
.如果当前任务的顶部已存在 Activity 的一个实例,则系统会通过调用该实例的 onNewIntent()
方法向其传送 Intent,而不是创建 Activity 的新实例。Activity 可以多次实例化,而每个实例均可属于不同的任务,并且一个任务可以拥有多个实例(但前提是位于返回栈顶部的 Activity 并不是 Activity 的现有实例)
比如现在假设应用程序A 有两个activity a, b. 现在的情况是先打开了a,然后在a中打开b,a的启动模式是"standard",b启动模式是"singleTop",a中启动b时没有添加flag,这样a,b是在同一个task中,现在在b中再启动b,那么结果是不会创建b的实例,只是回到b的onNewIntent()
方法,看源码:
④
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
....
if (sourceRecord == null) {
// This activity is not being started from another... in this
// case we -always- start a new task.
if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
....
}
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
..
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
....
}
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
...
}
boolean addingToTask = false;
boolean movedHome = false;
TaskRecord reuseTask = null;
if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
....
}
...
if (r.packageName != null) {
// 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.
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null) {
if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
if (top.app != null && top.app.thread != null) {
if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP//b 的启动模式是 single top
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
....
if (doResume) {
resumeTopActivityLocked(null);//直接启动最上面的activity 也就是b
}
ActivityOptions.abort(options);
.....
top.deliverNewIntentLocked(callingUid, r.intent);//这里最终回调b activity的 onNewIntent()方法
return ActivityManager.START_DELIVERED_TO_TOP;
}
}
}
}
} else {
if (r.resultTo != null) {
...
}
....
}
当然还有很多种组合情况,这里就不一一列举了,还是看源码.
三:"singleTask"
.系统创建新任务并实例化位于新任务底部的 Activity。但是,如果该 Activity 的一个实例已存在于一个单独的任务中,则系统会通过调用现有实例的 onNewIntent()
方法向其传送 Intent,而不是创建新实例。一次只能存在 Activity 的一个实例.
这启动模式和启动标识FLAG_ACTIVITY_NEW_TASK有相同的功能.先查找目标activity是否有相关联的任务,如果有则肯定会在这个任务中启动(其中又有许多中情况等下看源码),如果不存在相关任务,则创建一个新的任务,在任务中启动目标activity.
看一下源码:
⑤
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
.....
int launchFlags = intent.getFlags();
....
if (sourceRecord == null) {
....
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
...
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {//看到这里,就是当activity的启动模式是这两种的时候
// The activity being started is a single instance... it always
// gets launched into its own task.
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;//启动标记被赋值了FLAG_ACTIVITY_NEW_TASK
}
....
}
所以③和⑤加上启动标识 flag 是FLAG_ACTIVITY_NEW_TASK 这三种情况 的作用是一样的,就是给launchFlags赋值为FLAG_ACTIVITY_NEW_TASK.
现在有两种情况当时验证的时候也困扰我一会,最后是通过看源码知道了原因.
TaskRecord{415d12f0 #6 A com.example.b U 0}
Run #6: ActivityRecord{414f0380 u0 com.example.b/.Main2Activity}
Run #5: ActivityRecord{415fdd50 u0 com.example.b/.MainActivity}
TaskRecord{415312c0 #5 A com.example.a U 0}
Run #4: ActivityRecord{415fcc40 u0 com.example.a/.Main2Activity}
Run #3: ActivityRecord{414c54d0 u0 com.example.a/.MainActivity}
现在系统任务的情况如上.有两个应用程序A ,B ,两个应用程序中分别有两个activity,四个activity的启动模式都是standard.启动的顺序是先启动A应用程序的第一个activity,这里启动添加了FLAG_ACTIVITY_NEW_TASK标志,所以看上面系统任务的情况知道,A应用程序的第一个activity是在任务的最下面,接着启动A应用程序的第二个activity,没有添加启动标识,所以A应用程序的两个activity是在同一个任务中415312c0 #5,然后在A 应用程序的第二个activity 中启动B应用程序的第一个activity,这里启动添加了FLAG_ACTIVITY_NEW_TASK标志,B应用程序的第一个activity是在任务(415d12f0 #6)的最下面,然后继续在B应用程序的第一个activity中启动它的第二activity,没有加启动标识.目前系统的任务情况就如上面所示了.现在我要做的是在,B应用程序第二个activity中去启动第一个activity,同时添加启动标识FLAG_ACTIVITY_NEW_TASK.结果如:
TaskRecord{415312c0 #5 A com.example.a U 0}
Run #6: ActivityRecord{415fcc40 u0 com.example.a/.Main2Activity}
TaskRecord{415d12f0 #6 A com.example.b U 0}
Run #5: ActivityRecord{414f0380 u0 com.example.b/.Main2Activity}
Run #4: ActivityRecord{415fdd50 u0 com.example.b/.MainActivity}
TaskRecord{415312c0 #5 A com.example.a U 0}
Run #3: ActivityRecord{414c54d0 u0 com.example.a/.MainActivity}
通过上面系统任务状态可以知道,现在位于最前面的是A 应用程序的第二个activity,而不是第一个.是不是有点奇怪? 看看源码:⑥
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
....
int launchFlags = intent.getFlags();
...
if (sourceRecord == null) {
...
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
...
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
...
}
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
...
}
boolean addingToTask = false;
boolean movedHome = false;
TaskRecord reuseTask = null;
if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// If bring to front is requested, and no result is requested, and
// we can find a task that was started with this same
// component, then instead of launching bring that one to the front.
if (r.resultTo == null) {
// See if there is a task to bring to the front. If this is
// a SINGLE_INSTANCE activity, there can be one and only one
// instance of it in the history, and it is always in its own
// unique task, so we do a special search.
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)
: findActivityLocked(intent, r.info);
if (taskTop != null) {//这里就不为空了,因为A应用程序已经启动过了,它的第一个activity相关的任务也就有了
if (taskTop.task.intent == null) {
...
}
// If the target task is not in the front, then we need
// to bring it to the front... except... well, with
// SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
// to have the same behavior as if a new instance was
// being started, which means not bringing it to the front
// if the caller is not itself in the front.
ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);//这里正在运行的B应用程序的第二个activity
if (curTop != null && curTop.task != taskTop.task) {//两个应用程序的任务不相同
r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
boolean callerAtFront = sourceRecord == null
|| curTop.task == sourceRecord.task;
if (callerAtFront) {
// We really do want to push this one into the
// user's face, right now.
movedHome = true;
moveHomeToFrontFromLaunchLocked(launchFlags);
moveTaskToFrontLocked(taskTop.task, r, options);//这做了任务切换的操作,也就是将A应用程序的所以在任务切换到前台,然后还将任务中最上面的activity启动起来,就是A应用程序的第二个activity.
options = null;
}
}
// If the caller has requested that the target task be
// reset, then do so.
if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
...
}
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
....
}
if ((launchFlags &
(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
== (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
...
} else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
...
} else if (r.realActivity.equals(taskTop.task.realActivity)) {//这里很关键,这个条件是当前是成立,r.realActivty是A应用程序的第一个activity,就是我们要
// In this case the top activity on the task is the//启动的activity,tasktop.task.realActivity就是A应用程序所在任务的真正activity是哪个,现在任务中
// same as the one being launched, so we take that//有两个activity,就是A应用程序的两个activity,到底是哪一个呢?答案是第一个activity,这里可以
// as a request to bring the task to the foreground.//认为创建这个任务的activity才是这个任务的realActivity,显然,是第一个activity
// If the top activity in the task is the root
// activity, deliver this new intent to it if it
// desires.
if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP)
&& taskTop.realActivity.equals(r.realActivity)) {
...
} else if (!r.intent.filterEquals(taskTop.task.intent)) {
..
}
} else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
..
} else if (!taskTop.task.rootWasReset) {
..
}
if (!addingToTask && reuseTask == 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.
if (doResume) {
resumeTopActivityLocked(null, options);//走到这里,直接运行最上面的activity,这时最上面的activity就是A应用程序的第二个activity了 因为
} else {//前面切换任务的时候已经启动起来了
ActivityOptions.abort(options);
}
return ActivityManager.START_TASK_TO_FRONT;
}
}
}
}
......
}
上面的情况,如果我启动是A应用程序的第二个activity呢,同样加FLAG_ACTIVITY_NEW_TASK,结果:
TaskRecord{41670c88 #5 A com.example.a U 0}
Run #8: ActivityRecord{415017d8 u0 com.example.a/.Main2Activity}
TaskRecord{4166a770 #6 A com.example.b U 0}
Run #7: ActivityRecord{4166a820 u0 com.example.b/.Main2Activity}
Run #6: ActivityRecord{416644a0 u0 com.example.b/.MainActivity}
TaskRecord{41670c88 #5 A com.example.a U 0}
Run #5: ActivityRecord{414e2c10 u0 com.example.a/.Main3Activity}
Run #4: ActivityRecord{416c3db0 u0 com.example.a/.Main2Activity}
Run #3: ActivityRecord{415bcd38 u0 com.example.a/.MainActivity}
这里我只是在A应用程序中多加了一个activity,其他启动顺一样,上面是启动A应用中第二个activity后,系统任务的情况.
分析以后,首先任务肯定是切换了,A应用所在的任务切换到了前台,其次在A应用所在的任务中,创建了第二个activity的新实例,注意打印出来没在一起,但是它们确实是在41670c88 #5这个任务中.
所以也验证了A应用程序所在的任务的真正activity是第一个activity.
这里就没再分析源码了,大家有兴趣可以去看看.
其实这里面还有很多其它情况,比如,这些activity的启动模式设置为其他的模式,那么结果可能又不一样.大家可以去实验,然后结合源码分析.
四:"singleInstance"
.与 "singleTask"
相同,只是系统不会将任何其他 Activity 启动到包含实例的任务中。该 Activity 始终是其任务唯一仅有的成员;由此 Activity 启动的任何 Activity 均在单独的任务中打开
这个启动模式就不再举例了,前面源码也有分析到了一些情况.
关于启动标识,我这里是重点讲到了FLAG_ACTIVITY_NEW_TASK,还有其他flag,FLAG_ACTIVITY_SINGLE_TOP,FLAG_ACTIVITY_CLEAR_TOP.....就没有一一介绍,大家查阅资料.
另外
元素的 taskAffinity
属性提一下:
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
....
if (r.resultTo == null) {
// See if there is a task to bring to the front. If this is
// a SINGLE_INSTANCE activity, there can be one and only one
// instance of it in the history, and it is always in its own
// unique task, so we do a special search.
ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
? findTaskLocked(intent, r.info)//在这个方法里面,用到taskAffinity去查找与该activity相关的task
: findActivityLocked(intent, r.info);
....
如果一个Activity没有显式的指明该 Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果 Application也没有指明,那么该taskAffinity的值就等于包名。而Task也有自己的affinity属性,它的值等于它的根 Activity的taskAffinity的值.