Activity有四种启动模式,在介绍这四种启动模式之前,我们需要先知道,为什么Google会为Activity设置四种启动模式呢?
我们先来介绍一个概念:任务栈
任务栈:
1,程序在创建时,会创建一个任务栈,这个任务栈的作用是用来存储启动和创建的Activity
2,此任务栈包含了一个集合,让存储的任务栈给用户有序的列出来,以至于不丢失他们的状态
3,任务栈用来保存Activity的状态
4,退出程序时,清除任务栈中的Activity,任务栈销毁,程序退出
任务栈的缺点:
1,每开启一次页面都会在任务栈中添加一个Activity,而只有任务栈中的Activity全部清除出栈时,任务栈被销毁,程序才会退出,这样就造成了用,户体验差, 需要点击多次返回才可以把程序退出了。
2,每开启一次页面都会在任务栈中添加一个Activity还会造成数据冗余, 重复数据太多, 会导致内存溢出的问题(OOM)。
为了解决任务栈的缺陷,Google才设置了四种启动模式
这四种启动模式如下:
- standard
- singleTop
- singleTask
- singleInstance
下面我们来介绍一下这四种启动模式在什么样的场景下使用?
- Standard
standard模式是默认的启动模式,不用为配置android:launchMode属性即可,当然也可以指定值为standard。
这个我们就不详细介绍了,平时我们用的都是这样的
standard的原理如下:
standard不管是否已经有了实例,都会进行创建,他们在任务栈中的序列号并不一样,每一次创建,都是一个全新的Activity
2.singleTop
如上的原理图,如果我们在清单文件中声明此Activity启动模式是singleTop的话,这样的情况下,singleTop定义的Activity跳转,将不会是重新创建的Actiivty,观看他们在栈中的序列号就可以知道了
singleTop的原理图如下:
当然,这只是一个Activity的情况,那如果是多个Activity的情况下,他们之间的跳转又是什么样的呢?
我们通过打印他们跳转的Activity在栈中的序列号发现,FirstActivity跳转到SecondActiivty,再从SecondAcitivty跳转到FirstActivity时,他们所产生的序列号并不一样,这就证明,在SingleTop的模式下,当你不同Activity之间的跳转的时候,还是会新建一个Acitivyt的实例的
这时候的原理图如下:
在任务栈中的判断就是,当前的栈顶元素并不是FirstActivity,所以当你跳转时,他就会自动创建一个新的实例,压入栈顶
所以,SingleTop模式使用场景就是,如果当前的Activity是在栈顶的情况下,则重复使用,如果不在栈顶的情况下,则重新创建,比如说,我们写一个通讯的页面,接收到消息之后,弹出一个Activity,这个Activity是用来显示消息列表的,如果来了十条消息,我们还是用这个Activity来显示,总不能来了十条消息,就显示十个Activity吧?
3.singleTask
将上面的两个实例中FirstActivty的启动模式改为singleTask,打印之后发现,FirstActivty的序列号是不变的,SecondActivity的序列号却不是唯一的,说明从SecondActivity跳转到FirstActivty时,没有生成新的实例,但是从MainActivity跳转到SecondActivity时生成了新的实例。
原理图如下:
SecondActivity跳转到FirstActivty后的栈结构变化的结果,我们注意到,SecondActivity消失了,没错,在这个跳转过程中系统发现有存在的FirstActivity实例,于是不再生成新的实例,而是将FirstActivty之上的Activity实例统统出栈,将FirstActivty变为栈顶对象,显示到幕前。也许朋友们有疑问,如果将SecondActivity也设置为singleTask模式,那么SecondActivity实例是不是可以唯一呢?在我们这个示例中是不可能的,因为每次从SecondActivity跳转到FirstActivty时,SecondActivity实例都被迫出栈,下次等FirstActivty跳转到SecondActivity时,找不到存在的SecondActivity实例,于是必须生成新的实例。但是如果我们有ThirdActivity,让SecondActivity和ThirdActivity互相跳转,那么SecondActivity实例就可以保证唯一。
这就是singleTask模式,如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。
总之一句话,保证这种启动模式的Activity一直处于栈顶的位置,
singleTask适合作为程序入口点。例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。之前打开过的页面,打开之前的页面就ok,不再新建。
4,singleInstance
这种启动模式比较特殊,因为它会启用一个新的栈结构,将Activity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。
我们修改FirstActivity的launchMode=”standard”,SecondActivity的launchMode=”singleInstance”
原理图如下:
我们看到从MainActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,然后按下后退键,再次回到原始栈结构;图中下半部分显示的在SecondActivity中再次跳转到MainActivity,这个时候系统会在原始栈结构中生成一个MainActivity实例,然后回退两次,注意,并没有退出,而是回到了SecondActivity,为什么呢?是因为从SecondActivity跳转到MainActivity的时候,我们的起点变成了SecondActivity实例所在的栈结构,这样一来,我们需要“回归”到这个栈结构。
singleInstance适合需要与程序分离开的页面。例如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。
最后,附上一张Activity的启动流程