Activity是Android四大组件中最常用的组件了,而它的多种启动模式也是我们必须掌握的基本内容,今天我们就来了解一下它的各种启动模式的效果。
我们可以在AndroidManifest.xml中通过android:launchMode=”“中指定活动被启动时的启动模式,或者通过在启动活动的Intent中设置Flag来指定。
android:launchMode
通过android:launchMode设置的启动模式有四种:
- standard
- singleTop
- singleTask
- singleInstance
standard
Activity启动的标准默认模式,如果开发者不主动去设置activity的启动模式,则启动模式就默认是这个。这种启动模式会在每次启动Activity时,都创建一个新的实例。
singleTop
如果Activity的启动模式被指定成singleTop,则该活动被启动时,系统会先判断该活动是否已经处于栈顶,如果是,就不会再次创建实例,而是直接启动已经在栈顶的这个Activity,并且会调用onNewIntent()这个方法。这种启动模式一般适用于QQ聊天界面等场景。
singleTask
singleTask模式更像是singleTop的升级版,当启动被设置成singleTask模式的活动时,系统会检查该Activity是否已经存在于当前的活动栈,如果已经存在,则不会新建实例,而是直接启动已经存在的这个Activity,同时也会调用onNewIntent()方法。
需要注意的是,以上所说的情况的前提是在同一个app中启动singleTask模式的Activity,如果是启动别的app中的singleTask模式的Activity,则会新建一个任务栈。
举个例子:假设有一个App叫A,里面有一个Activity叫MainActivity,有一个App叫B,里面有一个Activity叫SingleTaskActivity,且该Activity是singleTask模式的。当A中的MainActivity启动B中的SingleTaskActivity时,如果B此时没有创建活动栈,则会创建一个新的活动栈,并将SingleTaskActivity放置进去。如果此时B已经存在活动栈,则SingleTaskActivity将会存在于该活动栈(前提是SingleTaskActivity没有设置android:taskAffinity属性),并且这个活动栈会被切换到前台。
借助一张官方的图,以便于大家更加直观地理解:
不管是哪种情况,singleTask模式的Activity在同一个活动栈里面只会存在一个实例,在重新启动已经存在的实例时会调用onNewIntent()。并且当切换到singleTask模式的Activity时,会将活动栈中原本在该singleTask模式的Activity之上的Activity全部销毁。
singleTask模式的Activity还能通过设置android:taskAffinity属性达到指定Activity的活动栈的效果。
singleInstance
singleInstance 模式与设置了android:taskAffinity属性的singleTask模式有点相似,前者会启用一个新的活动栈来管理Activity,且该活动栈只会存在该singleInstance模式的Activity,而后者的活动栈能存在多个Activity。singleInstance模式主要用于实现多个程序访问浏览器等情景,以便共享同一实例。与singleTop、singleTask模式一样,当启动已存在的Activity实例时,会调用onNewIntent()方法。
startActivityForResult的注意点
由于Android官方认为不同的活动栈之间是不应该传递数据的,因此,当使用startActivityForResult启动singleTask或者singleInstance模式的Activity时,onActivityResult方法中返回的resultCode为RESULT_CANCELED。
Intent Flag
通过Intent Flag设置的启动模式常用的主要有以下四种:
- Intent.FLAG_ACTIVITY_NEW_TASK
- Intent.FLAG_ACTIVITY_NO_HISTORY
- Intent.FLAG_ACTIVITY_CLEAR_TOP
- Intent.FLAG_ACTIVITY_SINGLE_TOP
FLAG_ACTIVITY_NEW_TASK
这个Flag通常用于从Service中启动Activity,因为Service中并不存在活动栈,所以使用这个Flag来创建一个新的活动栈,或者使用已存在的活动栈。
这个Flag也经常跟FLAG_ACTIVITY_CLEAR_TOP结合在一起使用。如果只使用FLAG_ACTIVITY_NEW_TASK,当目标Activity已经存在且目标Activity不处于栈顶时,显示在界面上的将会是目标Activity所存在的任务栈的栈顶Activity,此时通过addFlag方法将FLAG_ACTIVITY_CLEAR_TOP加上的话,就会把目标Activity之上的Activity清空掉从而展现目标Activity。例如在通知栏中打开Activity等场景经常用到这个组合。
总的来说,通过FLAG_ACTIVITY_NEW_TASK 启动Activity时,如果启动的是程序自己的Activity,且程序当前不存在任务栈,会新建一个任务,否则会使用已有的任务栈。如果是启动另一个程序的Activity,且另一个程序当前不存在任务栈,则会新建一个任务栈,否则会使用另一个程序本身已存在的任务栈放置新启动的Activity。
FLAG_ACTIVITY_NO_HISTORY
带有这个Flag的Activity在启动其他Activity之后,会被销毁。假设有3个Activity:A、B和C,A使用FLAG_ACTIVITY_NO_HISTORY启动B,然后B再启动C,这时候活动栈里面就只存在A和C。
FLAG_ACTIVITY_CLEAR_TOP
用FLAG_ACTIVITY_CLEAR_TOP启动Activity后,系统会将上一个相同的Activity实例以及在其之上的Activity销毁,然后重新在栈顶中创建实例。比如有Activity:A、B、C,活动栈结构为A-B-B-B-C,这时候C以FLAG_ACTIVITY_CLEAR_TOP模式启动B,活动栈的结构将变为A-B-B-B,此时栈顶的B是重新创建出来的,而不是通过onNewIntent()启动的。
如果想要通过onNewIntent()启动的话,可以在启动的Intent中通过addFlag方法添加FLAG_ACTIVITY_SINGLE_TOP,或者在Manifest中指定默认之外的启动模式。
FLAG_ACTIVITY_SINGLE_TOP
与使用android:launchMode = “singleTop”模式相同。
还有需要注意的是:假设有A、B两个Activity,且ActivityA在Manifest中已经定义了启动模式,当ActivityB启动A,并且在启动的Intent中定义了启动Flag时,Intent中的启动Flag将会覆盖Manifest中的启动模式。
好了,本篇到此结束,如有错漏,欢迎吐槽矫正,谢谢。