Activity启动模式总结

前言

相关文章其实很多了。通过对阅读调试相关源码后,我认为还是有必要按自己的理解梳理总结输出。

核心源码在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启动模式可以分成两类,设置了该属性的与未设置该属性的:

  1. 对于非Activity启动的Activity(比如Service或者通知中启动的Activity)需要显示的设置Intent.FLAG_ACTIVITY_NEW_TASK
  2. singleTask及singleInstance在AMS中被预处理后,隐形的设置了Intent.FLAG_ACTIVITY_NEW_TASK
  3. 启动模式是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
        f.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,否则就调用onNewItent
            if (!r.finishing) {
                r.finishIfPossible("clear-task-top", false /* oomAdj */);
                return null;
            }
        }

        return r;
    }

你可能感兴趣的:(android)