彻底弄懂活动四大启动模式
来源:互联网 发布:武汉知黛化妆品靠谱吗 编辑:程序博客网 时间:2024/05/22 05:09
最近遇到关于启动模式的问题比较多,索性我也深入的研究了下。我觉得对某个知识点的理解必须要动手操作才能印象深刻,
当我们多次启动同一个活动时,系统会创建多个实例,并把它们按照先进后出的原则一一放入任务栈中,当我们按回键时,就会有一个活动从任务栈顶移除,重复下去,直到任务栈为空,系统就会回收这个任务栈。但是这样以来,系统多次启动同一个活动时就会重复创建多个实例,这种做法显然不合理,为了能够优化这个问题,Android提供四种启动模式来修改系统这一默认行为。
standard,singleTop,singleTask ,oneInstance接下来
为了打印方便,定义一个基础活动,在其中创建方法和onNewIntent方法中打印出当前活动的日志信息,主要包括所属的任务,当前类的哈希码,以及taskAffinity的值。之后我们进行测试的活动都直接继承该活动
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
standard-默认模式
这个模式是默认的启动模式,即标准模式,在不指定启动模式的前提下,系统默认使用该模式启动活动,每次启动一个活动都会重写创建一个新的实例,不管这个实例存不存在, 。这种模式下,谁启动了该模式的活动,该活动就属于启动它的活动的任务栈中这个活动它的的onCreate(),在onStart(),的onResume()方法都会被调用。
配置形式:
- 1
- 1
使用案例:
对于标准模式,android:launchMode可以不进行声明,因为默认就是标准
。StandardActivity的代码如下,入口活动中有一个按钮进入该活动,这个活动中又有一个按钮启动StandardActivity。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
我们首先进入StandardActivity,进入后再点击进入标准的按钮,再按四次返回键不断返回。
输出的日志如下:
可以看到日志输出了四次StandardActivity的和一次MainActivity的,从MainActivity进入StandardActivity一次,后来我们又按了三次按钮,总共四次StandardActivity的日志,并且所属的任务栈的id都是2087,这也验证了谁启动了该模式的活动,该活动就属于启动它的活动的任务栈中这句话,因为启动StandardActivity的是MainActivity,而MainActivity的taskId是2087,因此启动的StandardActivity也应该属于id为2087的这个任务,后续的3个StandardActivity被被标准化这个对象启动的,因此也应该还是2087,所以taskId都是2087.并且每一个Activity的哈希码都是不一样的,说明他们是不同的实例,即“每次启动一个活动都会重写创建一个新的实例“
singleTop-栈顶复用模式
这个模式下,如果新的活动已经位于栈顶,那么这个活动不会被重写创建,同时它的onNewIntent方法会被调用,通过这个方法的参数我们可以去除当前请求的信息如果栈顶不存在该活动的实例,则情况与标准模式相同。需要注意的是这个活动它的onCreate(),onStart()方法不会被调用,因为它并没有发生改变
配置形式:
- 1
- 1
使用案例:
ActivitySingleTop。Java
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
OtherTopActivity.java
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
操作和标准模式类似,直接贴输日志
我们看到,除了第一次进入SingleTopActivity这个活动时间,输出的是onCreate方法中的日志,后续的都是调用了onNewIntent方法,并没有调用onCreate方法,并且四个日志的哈希码都是一样的,说明这是因为第一次进入的时候,栈中没有该实例,则创建,后续的三次发现栈顶有这个实例,然后直接复用,并且调用onNewIntent方法。那么假设栈中有该实例,但是该实例不在栈顶情况又如何呢?
我们先从MainActivity中进入到SingleTopActivity,然后再跳转到其他活动中,再从其他活动中跳回SingleTopActivity,再从SingleTopActivity跳到SingleTopActivity中,看看整个过程的日志。
我们看到从MainActivity进入到SingleTopActivity时间,新建了一个SingleTopActivity对象,并且任务id与MainActivity是一样的,然后从SingleTopActivity跳到其他活动时间,新建了一个其他活动,此时任务中存在三个活动,从栈底到栈顶依次是MainActivity,SingleTopActivity,OtherActivity,此时如果再跳到SingleTopActivity,即使栈中已经有SingleTopActivity实例了,但是依然会创建一个新的SingleTopActivity实例,这一点从上面的日志的hashCode可以看出,此时栈顶是SingleTopActivity,如果再跳到SingleTopActivity,就会复用栈顶的SingleTopActivity,即会调用SingleTopActivity的onNewIntent方法。这就是上述日志的全过程。
对以上内容进行总结
标准启动模式是默认的启动模式,每次启动一个活动都会新建一个实例不管栈中是否已经活动的实例
singleTop模式分3种情况
- 当前栈中已有该活动的实例并且该实例位于栈顶时,不会新建实例,而是复用栈顶的实例,并且会将Intent对象传入,回调onNewIntent方法
- 当前栈中已有该活动的实例但是该实例不在栈顶时,其行为和标准启动模式一样,依然会创建一个新的实例
- 当前栈中不存在该活动的实例时,其行为同标准启动模式
标准和singleTop启动模式都是在原任务栈中新建活动实例,不会启动新的任务,即使你指定了taskAffinity属性。
那么什么是taskAffinity属性呢,可以简单的理解为任务相关性。
- 这个参数标识了一个活动所需任务栈的名字,默认情况下,所有活动所需的任务栈的名字为应用的包名
- 我们可以单独指定每一个活动的taskAffinity属性覆盖默认值
- 一个任务的亲和力决定于这个任务的根活动(根活动)的taskAffinity
- 在概念上,具有相同的亲和力的活动(即设置了相同taskAffinity属性的活动)属于同一个任务
- 为一个活动的taskAffinity设置一个空字符串,表明这个活动不属于任何任务
很重要的一点taskAffinity属性不对标准和singleTop模式有任何影响,即时你指定了该属性为其他不同的值,这两种启动模式下不会创建新的任务(如果不指定即默认值,即包名)
指定方式如下:
- 1
- 1
- 1
- 1
singleTask-栈内复用模式
这个模式十分复杂,有各式各样的组合。在这个模式下,如果栈中存在这个活动的实例就会复用这个活动,不管它是否位于栈顶,复用时,会将它上面的活动全部出栈,并且会回调该实例的onNewIntent方法。其实这个过程还存在一个任务栈的匹配,因为这个模式启动时,会在自己需要的任务栈中寻找实例,这个任务栈就是通过taskAffinity属性指定。如果这个任务栈不存在,则会创建这个任务栈。
配置形式:
- 1
- 1
使用案例:
ActivitySingleTask.java
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
OtherTaskActivity.java
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
现在我们先不指定任何taskAffinity属性,对它做类似singleTop的操作,即从入口MainActivity进入SingleTaskActivity,然后跳到OtherActivity,再跳回到SingleTaskActivity。看看整个过程的日志。
当我们从MainActiviy进入到SingleTaskActivity,再进入到OtherActivity后,此时栈中有3个活动实例,并且SingleTaskActivity不在栈顶,而在OtherActivity跳到SingleTaskActivity时,并没有创建一个新的SingleTaskActivity,而是复用了该实例,并且回调了onNewIntent方法。并且原来的OtherActivity出栈了,具体见下面的信息,使用命令adb shell dumpsys活动可进行查看
可以看到当前栈中只有两个活动,即原来栈中位于SingleTaskActivity之上的活动都出栈了。
我们看到使用singleTask启动模式启动一个活动,它还是在原来的任务中启动。其实是这样的,我们并没有指定taskAffinity属性,这个说明和默认值一样,也就是包名,当MainActivity启动时创建的任务名字就是包名,因为MainActivity也没有指定taskAffinity,而当我们启动SingleTaskActivity,首先会寻找需要的任务栈是否存在,也就是taskAffinity指定的值,这里就是包名,发现存在,就不再创新新的任务,而是直接使用。当该任务中存在该活动实例时就会复用该实例,这就是栈内复用模式。这个
时候,如果我们指定SingleTaskActivity的taskAffinity值。
- 1
- 1
还是之前的操作。但是日志就会变得不一样。
我们看到SingleTaskActivity所属的任务栈的TaskId发生了变换,也就是说开启了一个新的任务,并且之后的OtherActivity也运行在了该任务上
打印出信息也证明了存在两个不同的任务
如果我们指定MainActivity的taskAffinity属性和SingleTaskActivity一样,又会出现什么情况呢。
没错,就是和他们什么都不指定是一样的。这个
时候,就有了下面的结论
singleTask启动模式启动活动时间,首先会根据taskAffinity去寻找当前是否存在一个对应名字的任务栈
- 如果不存在,则会创建一个新的任务,并创建新的活动实例入栈到新创建的任务中去
- 如果存在,则得到该任务栈,查找该任务栈中是否存在该活动实例
如果存在实例,则将它上面的活动实例都出栈,然后回调启动的活动实例的onNewIntent方法
如果不存在该实例,则新建活动,并入栈
此外,我们可以将两个不同App中的活动设置为相同的任务亲戚,这样虽然在不同的应用中,但是活动会被分配到同一个任务中去
我们再创建另外一个应用,指定它的taskAffinity和之前的一样,都是com.xingyu.demo.singletask
- 1
- 1
然后启动一个应用,让他跳转到该活动后,再按home键后台,启动另一个应用再进入该活动,看日志
我们看到,指定了相同的taskAffinity的SingleTaskActivity和OtherActivity被启动到了同一个任务中,taskId都为2169。
singleInstance-全局唯一模式
该模式具备单一模式的所有特性外,与它的区别就是,这种模式下的活动会单独占用一个任务栈,具有全局唯一性,即整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的活动实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的活动在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
配置形式:
- 1
- 1
使用案例:
增加一个活动如下:
ActivitySingleInstance.java
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
使用下面的方式分别在两个应用中启动它
- 1
- 2
- 3
- 1
- 2
- 3
做的操作和上一次是一样的,查看日志
我们看到,第一个应用启动SingleInstanceActivity时,由于系统中不存在该实例,所以新建了一个任务,按主键后,使用另一个App进入该活动,由于系统中已经存在了一个实例,不会再创建新的任务,直接复用该实例,并且回调onNewIntent方法。可以从他们的哈希码中可以看出这是同一个实例。因此我们可以理解为:SingleInstance模式启动的活动在系统中具有全局唯一性。
- 彻底弄懂活动四大启动模式
- 彻底弄懂Activity四大启动模式
- 彻底弄懂Activity四大启动模式
- 彻底弄懂Activity四大启动模式
- 彻底弄懂Activity四大启动模式
- 彻底弄懂Activity四大启动模式
- 彻底弄懂Activity四大启动模式
- Android 彻底弄懂Activity四大启动模式 和taskAffinity属性详解 intentFlag 图文解析
- 彻底弄懂CSS盒子模式
- 彻底弄懂CSS盒子模式
- 彻底弄懂CSS盒子模式
- 彻底弄懂CSS盒子模式
- 彻底弄懂CSS盒子模式
- 彻底弄懂CSS盒子模式
- 一分钟让你彻底清楚Android四大启动模式
- 四大组件之活动(Intent、生命周期、启动模式)
- 彻底弄懂CSS盒子模式之三
- 彻底弄懂CSS盒子模式之一
- Java length、length()、size()区别
- 删除用户时提示“数据库主体在该数据库中拥有架构”无法删除解决办法
- Js控制文本框只能输入数字或小数点
- Git项目管理+Unity游戏开发——在Git上布置一个Unity空项目
- js中escape,encodeURI和encodeURIComponent区别
- 彻底弄懂活动四大启动模式
- java学习笔记------数组
- java实现excel的导入导出(poi详解)
- JsBridge实现及原理
- JavaScript同步、异步、回调执行顺序之setTimeout面试题分析
- 用GDB调试程序(一)
- MindManager导图美化——导图样式
- apk 下载
- java 关键字finalize