Activity四种启动模式的认识
最近看了一些前辈的文章,有了一些新的认识,不仅仅是知识,包括对待事情的态度。记录下来,作为自己态度的见证。首先在android中对于Activity的实例是通过栈(Task)来进行管理的,栈是一种先进后出的数据结构。主要的操作就是进栈和出栈。简单的如下图所示。
Acticity的启动模式一共四种分别是standard singleTop singleTask singleInstance,他们的配置是在AndroidManifestwenjian里面通过android:launchMode设置的如
<activity
android:name=".SecondActivity"
android:launchMode="singleTop" />
下面对这四个模式分别讲解。
首先我的测试项目是在一个MainActivity里面放置了4个按钮,每个按钮对应一种不同的启动模式。然后在每个Activity的onCreate方法中打印了(TAG)类名,方法名,任务栈的id,和当前类的hashCode值,这个值可以用来判断是否新增加了该类的实例。打印语句 Log.e(TAG, “onCreate” + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());所有的测试都是从MainActivity开始的。
一。standard
这是Activity默认的启动效果,当你没有设置launchMode的时候就是这种效果,在这种模式下,只要启动一个Activity就会增加一个新的实例并添加进栈里面。这里我进入的FirstActivity(启动模式就是standard),当进入了FirstActivity之后我在FirstActivity中用一个按钮跳转连续启动了4次FirstActivity(实际中肯定不会有这种操作 这里是为了试验效果)可以看看打印信息
可以看到每次FirstActivity都执行了onCreate方法 并且每次hashCode值也是不一样的,所以就正式了开始说的每次启动都会创建新的实例并入栈。
二。singleTop
那就有问题了啊,我的实例既然已经在栈顶了,为什么还要重新创建呢?于是乎就有了第二种启动方式了,在这种模式下首先会检测栈顶是否是需要启动的Activity的实例,如果不是,就直接创建,如果是的话,就不在创建新的实例,而是调用Activity的onNewIntent方法来唤醒这个Activity(不会执行onCreate)。同样的首先我先从MainActivity进入到SecondActivity(启动模式是singleTop),同样在SecondActivity中连续启动几次SecondActivity。我们来看看打印信息
可以看到第一次进SecondActivity的时候执行的onCreate,之后启动的时候都是执行的onNewIntent方法,且每个SecondActivity的hashCode值是一样的,这就说明此时只有一个SecondActivity的实例。刚才已经说过了,由于SecondActivity已经在栈顶了,所以是不会再去创建实例的。
那么接下来我们来看看当栈的顶部不是SecondActivity的时候又会有什么情况出现呢?这次我先进入SecondActivity然后从SecondActivity跳到FirstActivity(standard模式)再跳到SecondActivity。也就是说SecondActivity不在栈顶了。同样看打印信息
很显然这次两个SecondActivity的hashCode值不一样了,也就证明创建了新的实例。
三。singleTask
这个模式相对于前面两个模式就显得更复杂了,不知道你有没有发现前面讲的两种启动模式的TaskId是一样的,也就是说前面的两种模式只是影响了Activity的实例,并没有影响栈的情况。因此这个模式我决定分成两个部分。首先第一种情况是不影响栈的时候。这种情况下会先检测栈中是否有实例,没有就创建,如果有就把该实例之上的其他实例全部移出栈。同样的这次先从MainActivity进入ThirdActivity(singleTask)再进入FirstActivity(standard)再跳到ThirdActivity,我们一起来看看打印信息。
可以简单分析一下,第一次进入ThirdActivity直接新建一个实例,接着进入FirstActivity此时FirstActivity也创建了实例(毕竟都是第一次进来,肯定要创建的)这时候从FirstActivity跳转到ThirdActivity,由于栈里面已经有ThirdActivity的实例了,所以不会再创建而是调用了onNewIntent方法。
第二种,会影响栈的时候。在Activity里面还可以配置一个taskAffinity属性。
<activity
android:name=".ThirdActivity"
android:launchMode="singleTask"
android:taskAffinity="com.win.star" />
这个属性你可以把它理解成栈的名字,默认是工程下的包名(这个看到别的文章这么写的但是不知道怎么验证)。这次我们先从MainActivity进入到ThirdActivity(这次配置了taskAffinity)看看打印内容
可以看到两个TaskId是不一样的,这就说明他们进入了不同的栈。由于我们现在停留在ThirdActivity上,那么如果我们这是在ThirdActivity再上启动一个Activity的话,新的Activity(是standard模式)实例在哪个栈里面呢?看看结果
这个时候新启动的Activity实例位于ThirdActivity指定的新栈中,如果在ThirdActivity上再次启动指定了taskAffinity属性的Activity是否还会再创建一个新的栈呢?答案是会的。来看看结果
这里我把FirstActivity 和ThirdActivity都指定为singleTask且配置了不一样的taskAffinity。从MainActivity到ThirdActivity再到FirstActivity可以看到每个Activity的TaskId是不一样的然后再ThirdActivity与FirstActivity之间互相跳转始终都不会涉及到MainActivity那个栈。同理我也测试了第一个指定taskAffinity第二个不指定taskAffinity属性的还是直接看结果
这里的顺序是MainActivity–>ThirdActivity–>FirstActivity 其中ThirdActivity和FirstActivity启动模式都是singleTask,但是ThirdActivity我指定了taskAffinity而FirstActivity没有指定,结果发现FirstActivity的实例和MainActivity的实例在一个栈里面。(如果不理解就多想想指定和不指定有什么影响吧)
四。singleInstance
*(
该模式具备singleTask模式的所有特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性,即整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。)*我是这么理解这个模式,在该模式下创建Activity实例的时候会新开一个栈。且该栈中也只有这一个实例。首先还是从MainActivity进入到FourthActivity(模式是singleInstance)然后再进入到FirstActivity(模式是standard)先看结果
可以看到MainActivity和FirstActivity在一个栈里面,而FourThActivity在另外一个单独的栈里面。除了看打印的信息以为,你还可以在控制台输入命令adb shell dumpsys activity activities可进行查看结果如下
如果在singleInstance模式下再次启动一个模式为singleInstance的Activity还会继续新开一个栈的。这次测试顺序是这样的MainActivity–>FourthActivity(singleInstance) -->FiveActivity(singleInstance) --> FirstActivity(standard)
结果是这样的
最终FirstActivity和MainActivity在一个栈里面。其余两个都在不同的栈里面。由于这种组合实在太多了,有兴趣的可以自己多试试,源码太简单就是页面跳转。
最后做一下小总结。
1.standard:每次启动都会新建一个实例。
2.singleTop:启动时看是否有实例,没有就创建。如果有看是否在栈顶,如果在栈顶就直接复用不再新建否则会新建。
3.singleTask:首先看是否配置了taskAffinity,如果配置了就新开一个栈。如果没有配置就来看栈中是否有实例,如果有就将实例之上的其他实例移出栈,如果没有就新建。
4.singleInstance:新开一个栈,这个栈只有这一个实例对象。
最后本文是基于一些前辈的文章,结合自己的实际体验得到的结果。总的来说很多东西自己看看觉得没什么大不了的,但是当你自己去动手去实践真的会有所收获的。
参考文章:
彻底弄懂Activity四大启动模式
https://blog.****.net/mynameishuangshuai/article/details/51491074
最后的最后,鉴于笔者水平有限,若有错误,还望不吝赐教!