Activity的launchMode详细分析

本文从源码角度详细分析Android Activity的四种启动模式:standard、singleTop、singleTask和singleInstance,阐述它们在app内和app之间的行为差异,并探讨taskAffinity的影响。通过分析startActivityUncheckedLocked方法,揭示启动过程的关键逻辑。
摘要由CSDN通过智能技术生成

在研究了Activity的启动过程后,我觉得很有必要对Activity的launchMode进行分析一下,因为到目前为止,我发现网上对launchMode的讲解都是通过实例讲解,看完了总是似懂非懂的感觉,并没有根本上理解launchMode的原理。这里我会从源码的角度讲解launchMode。相信大家会和我一样,看了源码之后就会有一种豁然开朗的感觉。


Activity的启动模式一种有四种,分别如下:

1、standard

2、singleTop

3、singleTask

4、singleInstance


这里我们分两种情况讨论上述四种启动模式:app内和app之间

首先讨论app内

standard:不论当前任务栈中是否存在该Activity,都会新建一个Activity,如 任务栈为A B,要启动B 那么任务栈为 A B B

singleTop:如果当前要创建的Activity就在任务栈的顶端,那么不会创建新的Activity,仅仅调用Activity的onNewIntent,如果不在栈顶(或者栈中没有该Activity),那么还是会创建新的Activity,如任务栈为A B 启动B  任务栈变为 A B 如果 启动A 那么任务栈为 A B A

singleTask:如果当前任务中存在要启动的Activity,那么就不会创建新的Activity,如果不存在就会创建新的Activity,如任务栈为 A B C,启动B ,那么任务栈就会变为A B

singleInstance:将一个Activity的launchMode设置为该值时,表明这个Activity独自占用一个任务队列,这个队列中不让在加入其他的Activity

不同的app之间:

既然在不同的app之间,那么就说明是两个任务栈,并且有一个处理前台,一个运行在后台

standard:当前台的Activity启动后台任务的Activity,不管这个Activity在后台任务栈中是否已经存在,都会创建一个新的Activity,并将它加入前台的任务栈中

singleTop:如果前台的Activity启动后台任务的Activity,并且这个Activity已经在后台任务的栈顶,和app内不同的是,这里还不能确定是否会创建新的Activity,这里还需要看启动Activity的Intent里面是否有Intent.FLAG_ACTIVITY_NEW_TASK,如果此标记,那么就会将后台的任务队列移动到前端,如 前端任务栈 A B 后端任务栈 E F C,现在前端需要启动一个C,如果有Intent.FLAG_ACTIVITY_NEW_TASK,那么后端任务栈就会移到前端(并调用C的onNewIntent),前端栈退居后端。如果没有这个标记,那么仅仅就是在前端任务栈中创建一个新的Activity C。

singleTask:如果前台的Activity启动后台任务的Activity,不管这个Activity是否在栈顶,都会将后台的任务栈移到前台,前台任务栈移至后台。这里不需要考虑标记问题,因为被启动的Activity如果是singleTask,那么自动在启动Activity的intent中加入上述标记。

singleInstance:如果前台Activity启动后台任务的Activity,如果后台任务栈中已经有该Activity,那么就会调用该Activity的onNewIntent,并且后台任务还是在后台。如果后台任务栈中没有该Activity,那么会重新创建一个Acitivyt,并单独放入一个任务栈,其实在启动该Acitivity的Intent中也会加入上述标记


其实还有一种情况比较特殊,不过很少使用,就是在一个app之间,我们给某一个Activity配置了taskAffinity属性,这个属性会影响singleTask等属性,这个可以大家自己去分析。

下面我们就来看看和launchMode处理有关的代码吧

对launchMode处理的逻辑主要是放在了ActivityStack的startActivityUncheckedLocked方法中,这份方法的逻辑有些复杂,我们来一部分一部分的分析:

第一部分:

 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) {
                Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
                      + intent);
                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
            }
        } else if (sourceRecord.launchMode == ActivityInfo.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.
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
        } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
            // The activity being started is a single instance...  it always
            // gets launched into its own task.
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
        }


首先判断sourceRecord是否为Null(桌面启动一个Activity或者通过Context启动一个Activity时sourceRecord为null),如果在启动的Intent中没有FLAG_ACTIVITY_NEW_TASK那么就会在该Intent中添加该标记。

如果sourceRecord的launchMode设置的是singleinstance,那么就会在Intent添加FLAG_ACTIVITY_NEW_TASK,因为对于singleinstance的Activity,是不会和别人共享一个队列的。

如果被启动的Activity的launchMode是singleinstance或者singletask,那么也会在Intent中添加FLAG_ACTIVITY_NEW_TASK标记(上面我们已经说过)。



在看第二部分代码

        if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            // For whatever reason this activity is being launched into a new
            // task...  yet the caller has requested a result back.  Well, that
            // is pretty messed up, so instead immediately send back a cancel
            // and let the new task continue launched as normal without a
            // dependency on its originator.
            Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
            sendActivityResultLocked(-1,
                    r.resultTo, r.resultWho, r.requestCode,
                Activity.RESULT_CANCELED, null);
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值