Activity四种启动模式

网上有很多相关文章的介绍,这里就不多说了。只是通过案例来解释内容,因为有些内容理解起来还是比较费劲的,如果理解错了,那就得纠结好一阵子了。

standard

略过

singleTop

目前我了解两种情况,下面分别描述。
第一种:
当前任务栈:A-B-C-D
操作:D为singleTop,从D中再次启动D
此时的任务栈:A-B-C-D
D的生命周期为:onNewIntent() - onResume()。
结论:D没有重新创建,而是走了onNewIntent()和onResume()方法,需要注意不会走onStart()方法。

第二种:
当前的任务栈:A-B-C-D
操作:C为singleTop,从D中再次启动C
此时的任务栈:A-B-C-D-C
C的生命周期为:onCreate()-onStart()-onResume()。

结论:C重新创建了,这种情况C会出现多个实例。

使用Flag:
对应的Flag为Intent.FLAG_ACTIVITY_SINGLE_TOP
以上面第一种为例,删除D中的singleTop,还是在D中启动D:

        Intent intent = new Intent(this, D1.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        startActivity(intent);

我在这里犯了一个错误,不是在C1启动D1的时候设置的flag,而是在D1启动D1的时候设置flag。

singleTask

这个模式需要测试的情况比较多,下面分多个场景测试。

场景一:
当前的任务栈:A-B-C-D
操作:C为singleTask,从D中再次启动C
此时的任务栈:A-B-C
C的生命周期为:onNewIntent()-onStart-onResume。

结论:1:C没有重新创建,而是生命周期发生如上变化,这里我留意到比singleTop多走了onStart方法。
2:C上面的Activity D出栈了,这里C上面只有D,其实不管C上面有多少个Activity,都会出栈。

这里测试还没完,很多文章写的singleTask会创建一个新栈,我们看下是否真的创建了新栈。
日志如下:
07-19 15:22:58.276 20391-20391/com.lxq.app1 D/TaskId: 95—–A1
07-19 15:22:59.532 20391-20391/com.lxq.app1 D/TaskId: 95—–B1
07-19 15:23:00.390 20391-20391/com.lxq.app1 D/TaskId: 95—–C1
07-19 15:23:01.739 20391-20391/com.lxq.app1 D/TaskId: 95—–D1
07-19 15:23:04.082 20391-20391/com.lxq.app1 D/TaskId: 95—–C1

显然没有创建一个新栈,其实创建新栈指的是启动另外一个APP的时候会创建新栈,而不是在当前APP操作。于是继续测试。

准备工作:
App1中的Activity - A1,B1,C1,D1
App2中的Activity - A2,B2,C2,D2

操作:
App1中的A1启动App2中的B2,把B2的启动模式改为singleTask。

日志:
07-19 15:42:51.940 22780-22780/com.lxq.app1 D/TaskId: 106—–A1
07-19 15:42:56.189 22434-22434/com.lxq.app2 D/TaskId: 107—–B2

结论:同一个APP中,Activity设置singleTask并不会创建新的任务栈,App1启动App2中的设置有singleTask的Activity才会创建新的任务栈。那如果我非要在一个App中给不同Activity设置不同的栈,比如我要在App1中给A1,B1指定一个栈,给C1,D1指定一个栈,这个怎么解决。很多文章和书籍都有介绍如何实现,使用affinity。

在测试affinity之前,我想拿刚才介绍的例子做几个测试:
目前的情况:App1中的A1启动了App2中的B2,他们来自两个不同的任务栈,App1初始启动Activity为A1,App2初始启动Activity是A2。

第一个测试:
确保App2所有Activity完全关闭(专业点说就是没有后台任务栈哈),启动App1,在A1中启动App2的B2,
然后Home键进入桌面,点击App2的启动图标,正常情况下App2应该启动A2。

结论:点击App2后启动是B2,按返回键后回到桌面。因为App2的栈内之前不存在B2,所以这里B2的生命周期很明显是从onCreate开始的,那么问题来了,如果App2中,当前任务栈为A2-B2,然后按Home键回到桌面,再从App1中启动App2中的B2,此时的B2生命周期又是怎样的呢?继续测试。

第二个测试:
确保App2中的任务栈为A2-B2,然后Home键,在App1中的A1去启动App2中的B2,观察此时B2的生命周期。

日志:
07-19 16:45:21.438 3673-3673/com.lxq.app2 D/ActivityLife: A2 - onCreate
07-19 16:45:21.442 3673-3673/com.lxq.app2 D/ActivityLife: A2 - onStart
07-19 16:45:21.442 3673-3673/com.lxq.app2 D/ActivityLife: A2 - onResume
07-19 16:45:28.581 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onCreate
07-19 16:45:28.598 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onStart
07-19 16:45:28.599 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onResume
07-19 16:45:39.561 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onNewIntent
07-19 16:45:39.584 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onStart
07-19 16:45:39.585 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onResume

结论:生命周期 onNewIntent-onStart-onResume。这个很好理解,App2中任务栈为A2,B2,B2为singleTask所以B2在栈内是唯一的,当App1启动B2的时候不会创建新的实例,而是走onNewIntent()方法。其实这里还有一种场景,这个测试场景是App2中任务栈为A2-B2,那如果App2中的任务栈为A2-B2-C2-D2呢,其实我也不知道,我猜如果App1中的A1启动App2中的B2后,App2中的任务栈可能是A2-B2,B2的生命周期和上面相同onNewIntent-onStart-onResume。那就再麻烦一次了。

第三个测试:
确保App2中的任务栈为A2-B2-C2-D2,然后Home键,在App1中的A1去启动App2中的B2,观察此时B2的生命周期和APP2中的任务栈。

日志:
07-19 16:58:57.698 3673-3673/com.lxq.app2 D/ActivityLife: A2 - onCreate
07-19 16:58:57.703 3673-3673/com.lxq.app2 D/ActivityLife: A2 - onStart
07-19 16:58:57.703 3673-3673/com.lxq.app2 D/ActivityLife: A2 - onResume
07-19 16:58:59.439 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onCreate
07-19 16:58:59.470 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onStart
07-19 16:58:59.470 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onResume
07-19 16:59:01.201 3673-3673/com.lxq.app2 D/ActivityLife: C2 - onCreate
07-19 16:59:01.205 3673-3673/com.lxq.app2 D/ActivityLife: C2 - onStart
07-19 16:59:01.205 3673-3673/com.lxq.app2 D/ActivityLife: C2 - onResume
07-19 16:59:02.595 3673-3673/com.lxq.app2 D/ActivityLife: D2 - onCreate
07-19 16:59:02.602 3673-3673/com.lxq.app2 D/ActivityLife: D2 - onStart
07-19 16:59:02.602 3673-3673/com.lxq.app2 D/ActivityLife: D2 - onResume
07-19 16:59:09.970 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onNewIntent
07-19 16:59:10.004 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onStart
07-19 16:59:10.004 3673-3673/com.lxq.app2 D/ActivityLife: B2 - onResume

结论:此时的任务栈为A2-B2,B2的生命周期onNewIntent-onStart-onResume。上面我猜对了。

如果把上面三个测试归为一类,那么还是以上三个测试中的第一个测试,再做一个测试,回顾一下该测试的条件:App1中的A1启动App2中的B2,并且设置B2为singleTask,得到的结论是B2创建了一个新栈,那么问题又来了,如果B2不设置singleTask,这个时候B2是否在A1的栈内?

日志:
07-19 17:10:53.635 2907-2907/com.lxq.app1 D/TaskId: 134—–A1
07-19 17:10:57.182 25342-25342/com.lxq.app2 D/TaskId: 134—–B2

结论:B2在A1所在的栈内,通过B2进入C2,D2,都会在A1所在的栈内。刚才上面做了三个测试,这里就不做测试了,我测过了,直接下结论,如果是这种场景,不管APP2的栈内如何变化都与APP1没有关系,APP1每次启动APP2中B2都会创建一个新的实例,你点击APP2的启动图标,也不会显示B2,而是重新创建任务栈,显示A2。我是这样理解的,如果App2中的B2设置了singleTask,当App1中的A1启动App2中的B2的时候,会给App2创建一个新栈,然后把B2压入这个栈,当点击App2启动图标的时候,会去查找App2中是否有任务栈存在,如果有则激活最顶层的Activity,这样也就不难解释点击App2启动图标的时候,看到的不是A2,而是B2了。如果App2中的B2不设置singleTask,App1启动B2的时候都会放在启动B2的A1的栈内。

使用flag:
singleTask对应Intent.FLAG_ACTIVITY_NEW_TASK,据我测试,使用上他们并非完全等同。这里我分别作了两个测试:

第一个测试
在App1中,A1-B1-C1-D1,然后从D1再次启动B1,并设置
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

结论:最后的任务栈为A1-B1-C1-D1-B1,B1重建了,它们都在同一个任务栈。并没有在amanifest中设置singleTask的效果,不走onNewIntent()方法,也不会移除B1上面的的任务栈(不会移除C1,D1)。有人会说需要使用taskAffinity,我测过,使用taskAffinity只是会给B1分配一个新的任务栈,最后任务栈还是没变A1-B1-C1-D1-B1,只不过A1在一个任务栈,B1-C1-D1-B1在另外一个任务栈,还是不会走onNewIntent()方法,所以,总结为,在一个APP中,通过设置Intent.FLAG_ACTIVITY_NEW_TASK达不到singleTask的效果,当然我只是根据测试得出的结论,如果不对,欢迎纠正!

第二个测试
在App1中的A1去启动App2中的B2,并设置
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
这种方式和设置singleTask有很多不同,这里不细说了,自己可以测试一下。

现在解决上面提到的问题,在App1中给A1,B1指定一个栈,给C1,D1指定一个栈,这个怎么解决?使用affinity。

TaskAffinity

TaskAffinity属性主要和singleTask或allowTaskReparenting结合使用,其他情况没有意义。

TaskAffinity和singleTask结合使用

只需要给C1如下设置:

        <activity android:name=".C1"
            android:taskAffinity="com.lxq"
            android:launchMode="singleTask"
            />

07-20 04:57:22.851 10029-10029/com.lxq.app1 D/TaskId: 212—–A1
07-20 04:57:24.119 10029-10029/com.lxq.app1 D/TaskId: 212—–B1
07-20 04:57:25.161 10029-10029/com.lxq.app1 D/TaskId: 213—–C1
07-20 04:57:26.558 10029-10029/com.lxq.app1 D/TaskId: 213—–D1

TaskAffinity和allowTaskReparenting结合使用
现在使用App1中的A1启动App2中的B2,并且,B2设置为:

        <activity android:name=".B2"
            android:allowTaskReparenting="true"
            >
            <intent-filter>
                <action android:name="lxq.example.action" />
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

可以发现这里没有设置TaskAffinity,如果不设置TaskAffinity默认为包名。这里只是设置了一行代码而已:android:allowTaskReparenting=”true”。

现在做如下操作:
1.清空所有任务栈,启动App1,在A1中启动App2中的B2。
日志如下:

07-20 05:22:48.170 30685-30685/com.lxq.app1 D/ActivityLife: A1 - onCreate
07-20 05:22:48.172 30685-30685/com.lxq.app1 D/ActivityLife: A1 - onStart
07-20 05:22:48.173 30685-30685/com.lxq.app1 D/ActivityLife: A1 - onResume—-240—–A1
07-20 05:22:52.310 30377-30377/com.lxq.app2 D/ActivityLife: B2 - onCreate
07-20 05:22:52.319 30377-30377/com.lxq.app2 D/ActivityLife: B2 - onStart
07-20 05:22:52.322 30377-30377/com.lxq.app2 D/ActivityLife: B2 - onResume—-240—–B2

现在App1中的任务栈情况 A1-B2,而且他们在一个任务栈,属于A1的任务栈。
可以发现这时候A1和B2都在一个Task里面,id为240。

2.Home键返回桌面,点击App2的启动图标。

07-20 05:24:06.675 30377-30377/com.lxq.app2 D/ActivityLife: B2 - onStart
07-20 05:24:06.676 30377-30377/com.lxq.app2 D/ActivityLife: B2 - onResume—-239—–B2

显示的是B2二不是A2,而且B2没有走onCreate()方法,说明没有重建,而且任务栈Id变成了239。感觉是B2从App1中转移到了它App2的任务栈中,因为任务栈Id也变了。如果是转移,那么此时我回到桌面,再次点击App1,那么B2还在不在App1中呢,答案是不在。可以自己测试一下。如果测试到这一步,一定还会发现一个有趣的现象,现在B2转移到App2的栈中了,也就是App2的栈中只有B2,按返回键应该返回到桌面,但是实际上不是这样的,

日志如下:
07-20 05:29:44.606 4643-4643/com.lxq.app2 D/ActivityLife: B2 - onStart
07-20 05:29:44.608 4643-4643/com.lxq.app2 D/ActivityLife: B2 - onResume—-242—–B2
07-20 05:29:50.035 4643-4643/com.lxq.app2 D/ActivityLife: A2 - onCreate
07-20 05:29:50.039 4643-4643/com.lxq.app2 D/ActivityLife: A2 - onStart
07-20 05:29:50.039 4643-4643/com.lxq.app2 D/ActivityLife: A2 - onResume

并没有回到桌面,而是去创建A2了,很奇怪。

另外还有一个问题,在App1中,如果A1,B1,在一个栈,C1,D1在一个栈,上面有写,通过TaskAffinity可以实现。现在的栈内情况是 A1-B1-C1-D1,使用D1调用B1,栈内情况会变成C1-D1-A1-B1,如果D1调用A1,栈内情况为C1-D1-A1,B1会出栈。

下面提供测试项目,可以在这个基础上完成上面的测试。

下载测试案例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值