Activity的四种启动模式

因为要为了出去工作而准备面试了,所以有必要总结一下这一年多来学习Android的知识点,同时也能复习一下所学所得。有些虽然很基础,但有句老话叫“好记性不如烂笔头”。好了,废话不多说,就从基本的Activity启动模式开始。

设置Activity的启动模式

怎么设置Activity的启动模式呢?有两种方法:

  1. 在AndroidManifest.xml中,设置launchMode属性:

    1
    2
    3
    4
    5
    <activity
    android:name=".SecondActivity"
    android:label="@string/title_activity_second"
    android:launchMode="standard"
    android:theme="@style/AppTheme.NoActionBar"/>
  2. 在启动Activity的时候,设置setFlags:

    1
    2
    3
    Intent intent=new Intent(MainActivity.this,SecondActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
    startActivity(intent);

两种设置模式的方法还是有区别的,按照惯例Java代码中的优先级肯定高于xml代码中的,如果两种都存在的话,以Java代码中的为准。另外在AndroidManifest.xml中无法设置FLAG_ACTIVITY_CLEAR_TOP标识,在Java代码中无法指定singleInstance模式。

四种模式

standard:标准模式

系统的默认模式,如果你没有设置启动模式的话就是这个模式。标准模式下的特点是每启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。被创建的Activity实例的生命周期正常调用,也就是onCreate、onStart、onResume都会被调用。

在这种模式下,当我们多次启动同一个Activity的时候,系统就会创建多个实例并把他们一一放到任务栈中。任务栈是一种后进先出的结构,每当我们按一下返回键的时候,就会有一个Activity出栈。另外我发现微信有很多功能都是快速点击的话会创建多个Activity,比如快速点击两下朋友圈,就会创建两个朋友圈的Activity,我不知道这是微信有意为之还是程序员疏忽了这些细节问题。

《Android开发艺术探索》提到,如果用ApplicationContext去启动一个Activity的话,会报错。像这样:

1
2
Intent intent=new Intent(MainActivity.this,SecondActivity.class);
App.getContext().startActivity(intent);

我试了下果然报了这个错误:

1
android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

这是因为standard模式下的Activity会默认进入启动它的Activity所属的任务栈,但是直接用ApplicationContext去启动它的话并没有所谓的任务栈,所以报错了。解决这个问题的方法是为待启动的Activity一个标记位FLAG_ACTIVITY_NEW_TASK:

1
2
3
Intent intent=new Intent(MainActivity.this,SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
App.getContext().startActivity(intent);

这样就可以正常启动了,这时系统为它创建了一个新的任务栈,并且是以standard模式启动的。

singleTop:栈顶复用模式

这种模式下,待启动的Activity如果位于任务栈的栈顶,那么就不会新建这个Activity的实例了。同时它的onNewIntent方法会被调用,我们可以在此方法取出当前请求信息。要注意的是,这个Activity的onCreate和onStart方法并不会被系统调用,因为它并没有发生改变。

另外一种情况是,当这个Activity并不在任务栈的栈顶,这样的话新的Activity就会被以新实例的方式创建,onCreate、onStart、onResume都会被调用。

singleTask:栈内复用模式

这种模式下,相当于单例模式。单例模式相信大家都懂,单例模式就是要确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

Activity被创建出来,肯定需要一个任务栈,singleTask模式下启动此Activity首先需要判断有没有此Activity想要的任务栈,如果不存在就创建一个任务栈,并将此Activity压到栈中。如果任务栈已经存在,并且任务栈中也存在此Activity的实例,系统就会将此Activity调到栈顶,显示出来。也就是说,待启动的Activity在任务栈中如果已经存在,无论你启动多少次这个Activity都不会创建新的实例了,此时也会只调用onNewIntent方法。

singleInstance:单实例模式

这个模式可以理解为singleTask模式的加强版。此模式除了拥有singleTask模式所以的特性外,还有一点就是此模式的Activity只能单独的存在于一个任务栈中,由于栈内复用的特性,所以后续的请求均不会创建新的Activity实例了,除非这个任务栈被系统销毁了。

应用场景

standard

标准模式,这个就不用多说了吧。

singleTop

适合接收通知启动的内容显示页面。

例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。

singleTask

适合作为程序入口点。

例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent方法,并且会清空主界面上面的其他页面。

多处判断弹出登录界面。

应用里面经常要根据服务器返回的用户登录状态来判断用户是否还在线,是否需要重新登录。但是当多个接口同时请求的时候,如果你的处理方式都是非在线状态下就会弹出登录的Activity,就会弹出很多个登录的Activity,用户体验很差。这时你可以将登录的Activity的launchMode设置为singleTask,就不会弹出多个同样的登录Activity了。然后就可以放心的在每个判断用户在线的地方启动登录的Activity了。

singleInstance

闹铃的响铃界面。

你以前设置了一个闹铃:上午6点。在上午5点58分,你启动了闹铃设置界面,并按 Home 键回桌面,在上午5点59分时,你在微信和朋友聊天,在6点时,闹铃响了,并且弹出了一个对话框形式的 Activity(名为AlarmAlertActivity) 提示你到6点了(这个 Activity 就是以SingleInstance加载模式打开的),你按返回键,回到的是微信的聊天界面。这是因为 AlarmAlertActivity所在的 Task 的栈只有他一个元素, 因此退出之后这个 Task 的栈空了。如果是以SingleTask打开AlarmAlertActivity,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。

最后

关于Activity的四种启动模式介绍到此完毕~欢迎补充!另外有不足的地方,欢迎在下方评论,交流。

Share