简介

众所周知当我们多次启动同一个Activity时,系统会创建多个实例,并把它们按照先进后出的原则一一放入任务栈中,当我们按back键时,就会有一个activity从任务栈顶移除,重复下去,直到任务栈为空,系统就会回收这个任务栈。但是这样以来,系统多次启动同一个Activity时就会重复创建多个实例,这种做法显然不合理,为了能够优化这个问题,Android提供四种启动模式来修改系统这一默认行为。
进入正题,Activity的四种启动模式如下:
standard、singleTop、singleTask、singleInstance

详解

  • 图解

944365-2a2ec6069979f7d4.png

  • 四种启动模式的区别

944365-f8ff1efde0a29112.png

  • 启动模式的设置

    1. AndroidMainifest设置

      1. <activity android:launchMode="启动模式" //属性 //standard:标准模式 //singleTop:栈顶复用模式 //singleTask:栈内复用模式 //singleInstance:单例模式 //如不设置,Activity的启动模式默认为标准模式(standard) </activity>
    2. 通过Intent设置标志位

      1. Intent inten = new Intent (ActivityA.this,ActivityB.class);
      2. intent,addFlags(Intent,FLAG_ACTIVITY_NEW_TASK);
      3. startActivity(intent);
    3. 标志位属性: | 标记位属性 | 含义 | | —- | —- | | FLAG_ACTIVITY_SINGLE_TOP | 指定启动模式为栈顶复用模式(SingleTop) | | FLAG_ACTIVITY_NEW_TASK | 指定启动模式为栈内复用模式(SingleTask) | | FLAG_ACTIVITY_CLEAR_TOP | 所有位于其上层的Activity都要移除,SingleTask模式默认具有此标记效果 | | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | 具有该标记的Activity不会出现在历史Activity的列表中,即无法通过历史列表回到该Activity上 |

    4. 二者的区别:

      • 优先级不同
        Intent设置方式的优先级 > Manifest设置方式,即 以前者为准
      • 限定范围不同
        Manifest设置方式无法设定 FLAG_ACTIVITY_CLEAR_TOPIntent设置方式 无法设置单例模式(SingleInstance

实例测试

一. standard 默认模式

这个模式是默认的启动模式,即标准模式,在不指定启动模式的前提下,系统默认使用该模式启动Activity,每次启动一个Activity都会重写创建一个新的实例,不管这个实例存不存在,这种模式下,谁启动了该模式的Activity,该Activity就属于启动它的Activity的任务栈中。这个Activity它的onCreate(),onStart(),onResume()方法都会被调用。

  • StandardActivity
  1. public class StandardActivity extends BaseActivity {
  2. @Override
  3. protected void onCreate(@Nullable Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_standard);
  6. }
  7. public void intoStandard(View view) {
  8. //
  9. Intent intent = new Intent(this, StandardActivity.class);
  10. startActivity(intent);
  11. }
  12. }
  • AndroidMainifest配置

    1. <activity android:name=".lauch.StandardActivity" android:launchMode="standard"/>
  • 测试结果

  • 04-19 14:42:32.650 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: onCreate()方法**
    04-19 14:42:32.651 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:MainActivity TaskId: 141220 hasCode:236124913
    04-19 14:42:32.652 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
    04-19 14:42:32.789 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: : mainactivity
    04-19 14:42:37.518 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM:
    onCreate()方法
    04-19 14:42:37.519 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:StandardActivity TaskId: 141220 hasCode:159871428
    04-19 14:42:37.520 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
    04-19 14:42:46.730 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: *onCreate()方法

    04-19 14:42:46.731 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:StandardActivity TaskId: 141220 hasCode:266437347
    04-19 14:42:46.732 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
    在 StandardActivity 里面点击再次进入 StandardActivity 界面, 每次都会重新创建.

二. singleTop 栈顶复用

这个模式下,如果新的activity已经位于栈顶,那么这个Activity不会被重写创建,同时它的onNewIntent方法会被调用,通过此方法的参数我们可以去除当前请求的信息。如果栈顶不存在该Activity的实例,则情况与standard模式相同。需要注意的是这个Activity它的onCreate(),onStart()方法不会被调用,因为它并没有发生改变。

SingleTopActivity:

  1. public class SingleTopActivity extends BaseActivity {
  2. public static final String TAG = "MMM";
  3. @Override
  4. protected void onCreate(@Nullable Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_single_top);
  7. Log.e(TAG, "singleTop---onCreate: " );
  8. }
  9. @Override
  10. protected void onRestart() {
  11. super.onRestart();
  12. Log.e(TAG, "singleTop---onRestart: " );
  13. }
  14. @Override
  15. protected void onStart() {
  16. super.onStart();
  17. Log.e(TAG, "singleTop---onStart: " );
  18. }
  19. @Override
  20. protected void onResume() {
  21. super.onResume();
  22. Log.e(TAG, "singleTop---onResume: " );
  23. }
  24. @Override
  25. protected void onPause() {
  26. super.onPause();
  27. Log.e(TAG, "singleTop---onPause: " );
  28. }
  29. @Override
  30. protected void onStop() {
  31. super.onStop();
  32. Log.e(TAG, "singleTop---onStop: " );
  33. }
  34. @Override
  35. protected void onDestroy() {
  36. super.onDestroy();
  37. Log.e(TAG, "singleTop---onDestroy: " );
  38. }
  39. public void intoSingleTop(View view) {
  40. Intent intent = new Intent(this, SingleTopActivity.class);
  41. startActivity(intent);
  42. }
  43. public void intoOtherTop(View view) {
  44. Intent intent = new Intent(this, OtherTopActivity.class);
  45. startActivity(intent);
  46. }
  47. }

测试结果:

04-19 14:45:48.243 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: onCreate()方法*
04-19 14:45:48.243 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:SingleTopActivity TaskId: 141220 hasCode:195657931
04-19 14:45:48.244 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
04-19 14:45:48.308 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onCreate:
04-19 14:45:48.309 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onStart:
04-19 14:45:48.310 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onResume:
04-19 14:45:54.449 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onPause:
04-19 14:45:54.450 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: onNewIntent()方法
04-19 14:45:54.451 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: onNewIntent:SingleTopActivity TaskId: 141220 hasCode:195657931
04-19 14:45:54.453 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
04-19 14:45:54.456 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onResume:

从 MainActivity 进入 SingleTopActivity, 在 SingleTopActivity 中再次进入 SingleTopActivity ,回调 onNewIntent(), onResume() 方法.如果 SingleTopActivity 不在栈顶, 则和 standard 启动模式一样.例如, MainActivity -> SingleTopActivity -> StandardActivity -> SingleTopActivity, 测试结果如下:

04-19 14:51:52.280 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: onCreate()方法**
04-19 14:51:52.281 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:SingleTopActivity TaskId: 141220 hasCode:166151539
04-19 14:51:52.282 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
04-19 14:51:52.344 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onCreate:
04-19 14:51:52.345 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onStart:
04-19 14:51:52.346 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onResume:
04-19 14:51:54.589 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onPause:
04-19 14:51:54.609 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM:
onCreate()方法
04-19 14:51:54.610 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:OtherTopActivity TaskId: 141220 hasCode:97164262
04-19 14:51:54.611 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
04-19 14:51:54.948 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onStop:
04-19 14:52:00.706 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: *onCreate()方法

04-19 14:52:00.706 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:SingleTopActivity TaskId: 141220 hasCode:107675084
04-19 14:52:00.707 31456-31456/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
04-19 14:52:00.765 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onCreate:
04-19 14:52:00.766 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onStart:
04-19 14:52:00.768 31456-31456/com.kiwilss.lxkj.fourassembly E/MMM: singleTop—-onResume:

最下面的打印结果, SingleTopActivity 重新创建了.

总结:

  1. 当前栈中已有该Activity的实例并且该实例位于栈顶时,不会新建实例,而是复用栈顶的实例,并且会将Intent对象传入,回调onNewIntent方法
  2. 当前栈中已有该Activity的实例但是该实例不在栈顶时,其行为和standard启动模式一样,依然会创建一个新的实例
  3. 当前栈中不存在该Activity的实例时,其行为同standard启动模式

standard和singleTop启动模式都是在原任务栈中新建Activity实例,不会启动新的Task,即使你指定了taskAffinity属性。
那么什么是taskAffinity属性呢,可以简单的理解为任务相关性。

  • 这个参数标识了一个Activity所需任务栈的名字,默认情况下,所有Activity所需的任务栈的名字为应用的包名
  • 我们可以单独指定每一个Activity的taskAffinity属性覆盖默认值
  • 一个任务的affinity决定于这个任务的根activity(root activity)的taskAffinity
  • 在概念上,具有相同的affinity的activity(即设置了相同taskAffinity属性的activity)属于同一个任务
  • 为一个activity的taskAffinity设置一个空字符串,表明这个activity不属于任何task
    很重要的一点taskAffinity属性不对standard和singleTop模式有任何影响,即时你指定了该属性为其他不同的值,这两种启动模式下不会创建新的task(如果不指定即默认值,即包名)
    指定方式如下:
    三, singleTask 栈内复用

这个模式十分复杂,有各式各样的组合。在这个模式下,如果栈中存在这个Activity的实例就会复用这个Activity,不管它是否位于栈顶,复用时,会将它上面的Activity全部出栈,并且会回调该实例的onNewIntent方法。其实这个过程还存在一个任务栈的匹配,因为这个模式启动时,会在自己需要的任务栈中寻找实例,这个任务栈就是通过taskAffinity属性指定。如果这个任务栈不存在,则会创建这个任务栈。

SingleTaskActivity:

  1. public class SingleTaskActivity extends BaseActivity {
  2. @Override
  3. protected void onCreate(@Nullable Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_single_task);
  6. }
  7. public void intoSingleTask(View view) {
  8. Intent intent = new Intent(this, SingleTaskActivity.class);
  9. startActivity(intent);
  10. }
  11. public void intoOtherSingleTask(View view) {
  12. Intent intent = new Intent(this, OtherSingleTaskActivity.class);
  13. startActivity(intent);
  14. }
  15. }

总结:

singleTask启动模式启动Activity时,首先会根据taskAffinity去寻找当前是否存在一个对应名字的任务栈

  • 如果不存在,则会创建一个新的Task,并创建新的Activity实例入栈到新创建的Task中去
  • 如果存在,则得到该任务栈,查找该任务栈中是否存在该Activity实例
    如果存在实例,则将它上面的Activity实例都出栈,然后回调启动的Activity实例的onNewIntent方法
    如果不存在该实例,则新建Activity,并入栈
    此外,我们可以将两个不同App中的Activity设置为相同的taskAffinity,这样虽然在不同的应用中,但是Activity会被分配到同一个Task中去。

四.SingleInstance 全局唯一,单例

该模式具备singleTask模式的所有特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性,即整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。

SingleInstance:

  1. public class SingleInstanceActivity extends BaseActivity {
  2. @Override
  3. protected void onCreate(@Nullable Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_single_instance);
  6. }
  7. public void goToStanard(View view) {
  8. startActivity(new Intent(this,OtherSingleInstanceActivity.class));
  9. }
  10. }

测试:

  1. MainActivity -> SingleInstanceActivity -> OtherStandardActivity
    04-19 15:10:08.398 32297-32297/com.kiwilss.lxkj.fourassembly I/MMM: onCreate()方法**
    04-19 15:10:08.399 32297-32297/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:MainActivity TaskId: 141223 hasCode:236124913
    04-19 15:10:08.400 32297-32297/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
    04-19 15:10:08.538 32297-32297/com.kiwilss.lxkj.fourassembly E/MMM: : mainactivity
    04-19 15:10:12.717 32297-32297/com.kiwilss.lxkj.fourassembly I/MMM:
    onCreate()方法
    04-19 15:10:12.718 32297-32297/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:SingleInstanceActivity TaskId: 141224 hasCode:159871428
    04-19 15:10:12.719 32297-32297/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
    04-19 15:10:17.437 32297-32297/com.kiwilss.lxkj.fourassembly I/MMM: *onCreate()方法

    04-19 15:10:17.438 32297-32297/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:OtherSingleInstanceActivity TaskId: 141223 hasCode:64963019
    04-19 15:10:17.438 32297-32297/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
    SingleInstanceActivity会创建一个单独的任务栈, 而 OtherStandardActivity 会在 MianActivity 创建的任务栈, 点击返回 这是 先关闭 OtherStandardActivity, 回到 MainActivity 界面, 再点返回到 SingleIntanceActivity 界面.
  2. MainActivity -> SingleInstanceActivity -> OtherStandardActivity -> SingleInstanceActivity
    04-19 15:13:47.519 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: onCreate()方法**
    04-19 15:13:47.520 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:MainActivity TaskId: 141226 hasCode:236124913
    04-19 15:13:47.521 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
    04-19 15:13:47.673 32442-32442/com.kiwilss.lxkj.fourassembly E/MMM: : mainactivity
    04-19 15:13:49.572 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM:
    onCreate()方法
    04-19 15:13:49.574 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:SingleInstanceActivity TaskId: 141227 hasCode:159871428
    04-19 15:13:49.575 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
    04-19 15:13:50.766 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: *onCreate()方法

    04-19 15:13:50.767 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:OtherSingleInstanceActivity TaskId: 141226 hasCode:64963019
    04-19 15:13:50.768 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
    04-19 15:13:51.882 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: onNewIntent()方法
    04-19 15:13:51.883 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: onNewIntent:SingleInstanceActivity TaskId: 141227 hasCode:159871428
    04-19 15:13:51.884 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
    在 OtherStandardActivity 再次进入 SingleInstanceActivity, 没有重新创建, 回调 onNewIntent 方法, 点击回退 回到 OtherStandardActivity 界面, 再回退到 MainActivity 界面, 再回退退出.
  3. 从别的应用进入
    1. 在 SingleInstanceActivity 没有创建时, 直接在另一个应用进入
      04-19 15:18:55.832 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: onCreate()方法*
      04-19 15:18:55.833 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: onCreate:SingleInstanceActivity TaskId: 141229 hasCode:74368588
      04-19 15:18:55.835 32442-32442/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly
    2. 先创建 SingleInstanceActivity, 再进入
      04-19 15:20:10.243 915-915/com.kiwilss.lxkj.fourassembly I/MMM: onNewIntent()方法
      04-19 15:20:10.247 915-915/com.kiwilss.lxkj.fourassembly I/MMM: onNewIntent:SingleInstanceActivity TaskId: 141232 hasCode:159871428
      04-19 15:20:10.249 915-915/com.kiwilss.lxkj.fourassembly I/MMM: taskAffinity:com.kiwilss.lxkj.fourassembly

我们看到,第一个应用启动SingleInstanceActivity时,由于系统中不存在该实例,所以新建了一个Task,按home键后,使用另一个App进入该Activity,由于系统中已经存在了一个实例,不会再创建新的Task,直接复用该实例,并且回调onNewIntent方法。可以从他们的hashcode中可以看出这是同一个实例。因此我们可以理解为:SingleInstance模式启动的Activity在系统中具有全局唯一性。

参考

彻底弄懂Activity四大启动模式

Android基础:最易懂的Activity启动模式详解

demo