Activity 启动模式
学习自
《Android开发艺术探索》
https://blog.csdn.net/javazejian/article/details/52071885
https://blog.csdn.net/iromkoear/article/details/70198605
启动模式漫谈
大家都知道,在默认的情况下,我们如果多次启动一个Activity的话,那么就会创建多个Activity并依次存入 任务栈
中,但退出当前Activity的时候,存在任务栈中的Activity将会依次退回。但是每一次都创建一个Activity这种模式在很多的情况下是不适用的,Google 肯定也想到了这一点,为了解决一些特殊的问题,我们需要修改Activity的启动模式。Activity的启动模式如下:
- standard
- singleTop
- singleTask
- singleInstance
前奏-任务栈
- android任务栈又称为Task,它是一个栈结构,具有后进先出的特性,用于存放我们的Activity组件。
- 我们每次打开一个新的Activity或者退出当前Activity都会在一个称为任务栈的结构中添加或者减少一个Activity组件,因此一个任务栈包含了一个activity的集合, android系统可以通过Task有序地管理每个activity,并决定哪个Activity与用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。
- 在我们退出应用程序时,必须把所有的任务栈中所有的activity清除出栈时,任务栈才会被销毁。当然任务栈也可以移动到后台, 并且保留了每一个activity的状态. 可以有序的给用户列出它们的任务, 同时也不会丢失Activity的状态信息。
- 需要注意的是,一个App中可能不止一个任务栈,某些特殊情况下,单独一个Actvity可以独享一个任务栈。还有一点就是一个Task中的Actvity可以来自不同的App,同一个App的Activity也可能不在一个Task中。
前台任务栈与后台任务栈
当前处于活动状态下的任务栈,比如说我们从一个程序中按 HOME
键回到桌面,那么这时候 HomeActivity
所属的任务栈即 前台任务栈
,而我们我们刚才按Home见退出的程序所处于的任务栈就是 后台任务栈
.
总结:
前台任务栈: 处于活动状态下的任务栈。
后台任务栈: 非处于互动状态下的任务栈。
此处关于前后台任务的定义,是本人总结而来,并没找到权威依据,仅供参考 如有谬误敬请斧正。
如何设置启动模式
方式一: 通过修改AndroidMainfast 文件
<activity
android:name=".MainActivity"
android:configChanges="orientation"
android:launchMode="singleTask">
</activity>
方式二: 通过Intent来设置
var tempIntent = Intent(this, MainActivity::class.java)
tempIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
两种启动方式的区别
- 第二种方式优先级更高,当两种方式同时存在,以第二种为准。
- 第一种方式无法为Activity设置
FLAG_ACTIVITY_CLEAR_TOP
标识 - 第二种无法为Activity指定singleInstance
Standard
标准模式(系统默认为此模式),每次启动Activity都会创建一个新的实例,此模式下,谁启动了新的Activity那么,新的Activity将会被添加到启动者的任务栈中并且执行常规模式下的生命周期方法。
SingleTop
栈顶复用,如果Activity在任务栈的顶部,那么不会创建,此时 onNewIntent
方法会被调用,可以通过此方法来获取一些相关的参数但是Activity的声明周期方法 onCreate
onStart
不会执行。如果将要被创建的Activity的实例不存在与栈顶,或者不存在于栈内,则重新创建实例。
SingleTask
栈内复用模式(单例模式) ,如果Activity存在于其__想要的__栈内,那么无论创建多少次都不会建立新的实例,创建Activity时,首先先寻找是否存在其想要的栈,如果不存在那么建立该栈并创建新的实例压入栈中,如果其想要的栈是存在的,首先会检测其中有没有该Activity的实例,如果有则提到栈顶并调用 onNewIntent
方法。如果不存在于栈内,则创建实例并压入栈中。
当SingleTask模式下的Activity的实例存在于其想要的栈中但是没有在该栈的栈顶的位置的时候,会出现这样的情况。比如栈中有ABCD四个Activity其中D位于栈顶,这是用要创建B的实例,因为这时候B已经存在于栈内了,但是由于singleTask启动模式下有clearTop(在指定Activity之上的Activity都将会出栈)的特性,现栈中的Activity仅仅剩下了AB,B位于栈顶。这一特性也是因为栈这种数据结构的__先进后出的特性__决定的。具体如下图:
SingleInstance
单实例模式,可以看做是 singleInstance
模式的加强版,次模式不仅仅具有 singleInstance
的一些特性,还做出了一些改变,来更满足单实例的需求,当创建一个不存在于栈中的Activity的时候, 系统会为此Activity创建一个独立的栈,这个栈中有且只有此Activity,根据栈内复用的机制,除非是该栈被销毁了,否则是不会创建新的实例的。
设置Activity的任务栈
在上面的 SingleTask
启动模式中,提到了__Activity自己想要的栈__,是通过 TaskAffinity
属性设置的。
PS: 该属性只有在 singleTask
启动模式下或者与 allowTaskReparenting
属性相结合的时候才会作用。
<activity
android:name=".MainActivity"
android:configChanges="orientation"
android:launchMode="singleTop"
android:taskAffinity="S1">
</activity>
AllowTaskReparrenting
现假设条件:
- 我们现在有两个程序APP-A和APP-B
- APP-B中有个lunchMode 为singleTask的ActivityTest
- APP-B中有主Activity-ActivityHome
- ActivityTest的allowTaskReparrenting属性为true
- ActivityTest的任务栈的名称和APP-A中的任务栈的名称不相同
现在在APP-A中打开了APP-B的ActivityTest,因为ActivityTest的TaskAffinity的任务栈不存在,所以新建一个任务栈并创建任务的实例,这时候按 HOME
键返回桌面,打开APP-B这是你会发现出现的不是APP-B的主界面-ActivityHome而是ActivityTest。
这是因为APP-A穿件了APP-B的ActivityTest,这时候ActivityTest只能运行在是APP-A的任务栈中,但是当APP-B被运行时,系统发现ActivityTest想要的任务栈被创建了,所以将ActivityTest从APP-A的任务栈中转移了出来。
我在网上找到了一个比较通俗的解释:
有点像,你捡到一条狗,在家里喂养几天觉得不错,当自己家的了;但是突然有一天他的主人找上门来了,小狗还是乖乖和主人走了。。。
总结
由于篇幅原因,本章提到的Activity的标志位将另开一章来记录。文中如果有任何谬误的话,敬请斧正。