说真的,Activity是四大组件里面我最经常使用的,设置过屏幕方向,设置过键盘隐藏等等,但就是没有关注过启动模式,所以特地学习了一下,做个记录。
在这之前,先了解两个重要概念:
1.Activity栈
栈是一种常用的数据结构,特点是“先入后出”或者说“后入先出”,意思是后放进去的元素会被先拿出来,就像把羽毛球放进羽毛球筒里面一样,最后一个放进去的羽毛球会被第一个拿出来。
Android的管理主要是通过Activity栈来进行,当一个Activity启动时,系统会根据其配置将它压入到一个特定的栈中,这个栈就是Activity栈。
2.Task
Task是一个具有栈结构的对象,就Activity而言,就是一组以栈的模式聚集在一起的Activity组件集合,一个应用起码具有一个Task。
好了,接下来首先说怎么设置启动模式,在清单文件activity标签内添加,eg:
<activity
android:launchMode="standard"
...>
可以很清楚地看到Android提供了四种launchMode:
- standard
- singleTop
- singleTask
- singleInstance
standard
“标准“,这是默认的launchMode,可以不用设置,这是最无脑的一种模式,这种模式的Activity被启动的时候,无论Task里面是否已经存在该Activity的实例,都会重新创建一个Activity实例放入Task。
eg:在一个应用的Task中,由栈顶到栈底已经存在了Aa、Ab、Ac,其中Ab的启动模式是standard,那么Ab被启动的时候,Task里面就变成了Ab、Aa、Ab、Ac。
注意:在Task中可以存在多个standard模式的Activity实例。
singleTop
single:单个、Top:顶端。其实这几个模式的起名都非常符合它们自身的特征。singleTop模式的Activity_singleTop被启动的时候,没那么无脑,首先检索栈顶(Top)的Activity实例,有两种情况:
1.栈顶的Activity实例不是Activity_singleTop:创建Activity_singleTop实例,放入Task;
2.栈顶的Activity实例就是Activity_singleTop:不创建Activity_singleTop实例,也就不调用Activity_singleTop的生命周期函数,调用一次onNewIntent(Intent intent);
注意:在栈顶之外的其它位置,还是允许有同样的singleTop模式的Activity实例的。
适用场景:譬如当前Activity设置了singleTop,界面上有一个按条件排序的列表,当更换排序条件的时候,直接跳转自身,从onNewIntent(Intent intent)接收intent获得新的排序条件,重新获得列表数据,绘制列表;或者会被Notification启动的Activity等。
singleTask
和singleTop有点类似,不过有两点不一样。
1.singleTask模式的Activity_singleTask被启动的时候,会检索全栈(Task)而不仅仅是栈顶的Activity_singleTask实例,整个Task里面没有Activity_singleTask实例的时候就会创建并放入Task中;
2.发现已经存在Activity_singleTask实例时,也有两种情况:
① Activity_singleTask实例在栈顶,那么同样地只调用onNewIntent(Intent intent);
②Activity_singleTask实例不在栈顶而在Task的其它位置,会将在Activity_singleTask之上的所有Activity实例出栈,让Activity_singleTask实例处于栈顶。
注意:
1.在栈中只能存在一个singleTask模式的Activity实例;
2.如果singleTask模式的Activity实例被其它应用程序启动,那么该实例会存放在一个新建的Task(Task_New)中,而由该实例Activity启动的Activity,同样会放在新建的Task_New中。
适用场景:通常用于设置为首页Activity的launchMode,那么无论首页跳转了多少个Activity之后,都可以在跳转会首页之后,在首页直接回退退出应用,而不用关注之前跳转过的Activity。
singleInstance
这是最复杂的一个启动模式,singleInstance模式下,会将打开的Activity_singleInstance放入一个新建的Task中。
eg1:Task1中结构为:A B C ,C通过Intent跳转到了D(D的模式为singleInstance),那么则会新建一个Task2,Task1中结构依旧为A B C,Task2中结构为D,此时屏幕中显示D。
1.之后D通过Intent跳转到D,Task2中不会压入新的D所以2个栈中的情况没发生改变;
2.D跳转到了C,那么就会根据C对应的launchMode的在Task1中进行对应的操作,C如果为standard,那么D跳转到C,Task1的结构为A B C C ,此时点击返回按钮,还是在C,Task1的结构变为A B C,而不会回到D;
3.其它应用打开D,发现已经有一个Task里面存在D,就直接打开,而不是再新建一个Task重新创建D实例。
可以理解为singleInstance模式的Activity,只要存在了实例,就是“系统唯一”的。
暂时就这么多,欢迎指正、交流。