前言
相关文章其实很多了。通过对阅读调试相关源码后,我认为还是有必要按自己的理解梳理总结输出。
核心源码在com.android.server.wm.ActivityStarter#startActivityInner
启动方式详解
Standard
默认模式,会直接在打开的Task上创建。不管taskAffinity
在不同Task中打开同一个Activity,Activity会被创建多个实例,分别放进每一个对应的Task。
SingleTop
与Standard相似,唯一的区别就是。
如果task顶部已经是该Activity,就不会创建新的,而是复用顶部Activity并通过onNewIntent
传输Intent给复用的Activity。
SingleTask(ATMS会添加FLAG_ACTIVITY_NEW_TASK)
启动的时候会在Activity的taskAfinity对应的task启动(task名称是第一个activity的taskAfinity)。
如果该task已经存在该activity,就将该activity上面的activity都退出,并将intent传到onNewIntent
。并将该task启动到前台(叠在当前的task上)
隐式添加FLAG_NEW_TASK
SingleInstance(ATMS会添加FLAG_ACTIVITY_NEW_TASK)
与SingleTask类似,但是会创建并独占一个task(名字与taskAfinity一致)。
这个时候会有两个相同(taskAfinity一样)的task,当再次启动这个Activity时,不会重建,只会调用onNewIntent
。并把该Task移动到前台。由于最近任务只能显示不同的taskAfinity的task,所以,这个时候去启动另外一个标准启动模式的OtherActivity会把OtherActivity的task切换到前台,并在OtherActivity对应的task上创建Activity,该Task与SingleInstance的那个Activity所在的Task同名(taskAffinitiy一样)。这个时候如果切换到最近任务列表(SingleInstance的那个Task会切到后台)再回来,点击返回按钮会发现SingleInstance的Activity不见了,包括在最近任务列表也不见了
computeLaunchingTaskFlags
private void computeLaunchingTaskFlags() {......if (mInTask == null) {if (mSourceRecord == null) {// This activity is not being started from another... in this// case we -always- start a new task.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) {// 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.mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;} else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {// The activity being started is a single instance... it always// gets launched into its own task.mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;//自动添加上FLAG_ACTIVITY_NEW_TASK}}}
特殊配置
allowTaskReparenting(FLAG_ALLOW_TASK_REPARENTING)
默认情况下,Activity只会归属于一个Task,如果设置allowTaskReparenting=true,这样activity可以在task之间切换。比如你A应用启动B应用的B Activity(只设置了allowTaskReparenting=true),那么B Activity就直接在A应用当前task上启动(到这里类似Standard的效果,但是在Android 9 10 有问题),然后这个时候打开B应用,A应用的B Activity就会移动到B的task上显示(到这里类似SingleTask)
FLAG分析
FLAG_ACTIVITY_NEW_TASK
从源码来看,Intent.FLAG_ACTIVITY_NEW_TASK是启动模式中最关键的一个Flag,依据该Flag启动模式可以分成两类,设置了该属性的与未设置该属性的:
- 对于非Activity启动的Activity(比如Service或者通知中启动的Activity)需要显示的设置Intent.FLAG_ACTIVITY_NEW_TASK
- singleTask及singleInstance在AMS中被预处理后,隐形的设置了Intent.FLAG_ACTIVITY_NEW_TASK
- 启动模式是standard及singletTop的Activity不会被设置Intent.FLAG_ACTIVITY_NEW_TASK,除非通过显示的intent setFlag进行设置。
Intent.FLAG_ACTIVITY_NEW_TASK的作用是在启动Activity时,ATMS会根据taskAffinity查找对应的Task,并将Activity添加到该Task中,然后启动。
如果不添加该Flag,就直接在发起请求的Task上启动目标Activity,否则就在目标Activity所对应的TaskAffinity的task中启动。由于Service没有对应的Task,所以通过Service启动Activity就必须要添加Intent.FLAG_ACTIVITY_NEW_TASK才行。
以Service启动的Activity为例。
Intent intent = new Intent(BackGroundService.this, A.class);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);
FLAG_ACTIVITY_CLEAR_TASK
必须配合FLAG_ACTIVITY_NEW_TASK一起使用。
当设置了FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
。如果目标task已经存在,将清空已存在的目标Task,否则,新建一个Task栈,之后,新建一个Activity作为根Activity。Intent.FLAG_ACTIVITY_CLEAR_TASK的优先级最高,基本可以无视所有的配置,包括启动模式及Intent Flag,哪怕是singleInstance也会被finish,并重建。
FLAG_ACTIVITY_CLEAR_TOP
清空源Activity所在Task中已存在的目标Activity之上的Activity,包括目标Activity也会被清空,然后重建目标Activity。
当与FLAG_ACTIVITY_SINGLE_TOP一起使用时,则不会清空目标Activity,而是重用(调用onNewIntent)
当与FLAG_ACTIVITY_NEW_TASK一起使用时,清空的task是目标Activity的taskAffinity对应的task,一直到目标Activity为止,不包含目标Activity
FLAG_ACTIVITY_SINGLE_TOP
单独使用,与SingleTop效果一样。
当与FLAG_ACTIVITY_CLEAR_TOP一起使用时,核心作用就是保证在清空源Activity所在Task顶部Activity的时候不会清空已存在的目标Activity,而是重用目标Activity,也就是调用onNewIntent
当与FLAG_ACTIVITY_NEW_TASK一起使用时,清空的Task是目标Activity的taskAffinity对应的task。
FLAG_ACTIVITY_MULTIPLE_TASK
这个标识用来创建一个新的task栈,并且在里面启动新的activity(所有情况,不管系统中存在不存在该activity实例),经常和FLAG_ACTIVITY_NEW_DOCUMENT或者FLAG_ACTIVITY_NEW_TASK一起使用。这上面两种使用场景下,如果没有带上FLAG_ACTIVITY_MULTIPLE_TASK标识,他们都会使系统搜索存在的task栈,去寻找匹配intent的一个activity,如果没有找到就会去新建一个task栈;但是当和FLAG_ACTIVITY_MULTIPLE_TASK一起使用的时候,这两种场景都会跳过搜索这步操作无条件的创建一个新的task。和FLAG_ACTIVITY_NEW_TASK一起使用需要注意,尽量不要使用该组合除非你完成了自己的顶部应用启动器,他们的组合使用会禁用已经存在的task栈回到前台。
源码分析清空Activity的逻辑
重建目标Activity的条件是:标准启动模式,并且没有FLAG_ACTIVITY_SINGLE_TOP,就是重建目标Activity,否则就只是调用onNewIntent
private ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {final ActivityRecord r = findActivityInHistory(newR.mActivityComponent);if (r == null) return null;final PooledFunction f = PooledLambda.obtainFunction(Task::finishActivityAbove,PooledLambda.__(ActivityRecord.class), r);forAllActivities(f);//这个方法主要是清空r(要启动的目标Activity)之上的Activityf.recycle();// Finally, if this is a normal launch mode (that is, not expecting onNewIntent()), then we// will finish the current instance of the activity so a new fresh one can be started.if (r.launchMode == ActivityInfo.LAUNCH_MULTIPLE //标准启动模式&& (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0 //不是SIGLE_TOP&& !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {//满足上面的条件就清空目标Activity,否则就调用onNewItentif (!r.finishing) {r.finishIfPossible("clear-task-top", false /* oomAdj */);return null;}}return r;}