简介
众所周知当我们多次启动同一个Activity时,系统会创建多个实例,并把它们按照先进后出的原则一一放入任务栈中,当我们按back键时,就会有一个activity从任务栈顶移除,重复下去,直到任务栈为空,系统就会回收这个任务栈。但是这样以来,系统多次启动同一个Activity时就会重复创建多个实例,这种做法显然不合理,为了能够优化这个问题,Android提供四种启动模式来修改系统这一默认行为。
进入正题,Activity的四种启动模式如下:
standard、singleTop、singleTask、singleInstance
详解
- 图解
- 四种启动模式的区别
启动模式的设置
AndroidMainifest设置
<activity android:launchMode="启动模式" //属性 //standard:标准模式 //singleTop:栈顶复用模式 //singleTask:栈内复用模式 //singleInstance:单例模式 //如不设置,Activity的启动模式默认为标准模式(standard) </activity>
通过
Intent
设置标志位Intent inten = new Intent (ActivityA.this,ActivityB.class);
intent,addFlags(Intent,FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
标志位属性: | 标记位属性 | 含义 | | —- | —- | | FLAG_ACTIVITY_SINGLE_TOP | 指定启动模式为栈顶复用模式(
SingleTop
) | | FLAG_ACTIVITY_NEW_TASK | 指定启动模式为栈内复用模式(SingleTask
) | | FLAG_ACTIVITY_CLEAR_TOP | 所有位于其上层的Activity都要移除,SingleTask
模式默认具有此标记效果 | | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | 具有该标记的Activity不会出现在历史Activity的列表中,即无法通过历史列表回到该Activity上 |二者的区别:
- 优先级不同
Intent
设置方式的优先级 >Manifest
设置方式,即 以前者为准 - 限定范围不同
Manifest
设置方式无法设定FLAG_ACTIVITY_CLEAR_TOP
;Intent
设置方式 无法设置单例模式(SingleInstance
)
- 优先级不同
实例测试
一. standard 默认模式
这个模式是默认的启动模式,即标准模式,在不指定启动模式的前提下,系统默认使用该模式启动Activity,每次启动一个Activity都会重写创建一个新的实例,不管这个实例存不存在,这种模式下,谁启动了该模式的Activity,该Activity就属于启动它的Activity的任务栈中。这个Activity它的onCreate(),onStart(),onResume()方法都会被调用。
- StandardActivity
public class StandardActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_standard);
}
public void intoStandard(View view) {
//
Intent intent = new Intent(this, StandardActivity.class);
startActivity(intent);
}
}
AndroidMainifest配置
<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:
public class SingleTopActivity extends BaseActivity {
public static final String TAG = "MMM";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_top);
Log.e(TAG, "singleTop---onCreate: " );
}
@Override
protected void onRestart() {
super.onRestart();
Log.e(TAG, "singleTop---onRestart: " );
}
@Override
protected void onStart() {
super.onStart();
Log.e(TAG, "singleTop---onStart: " );
}
@Override
protected void onResume() {
super.onResume();
Log.e(TAG, "singleTop---onResume: " );
}
@Override
protected void onPause() {
super.onPause();
Log.e(TAG, "singleTop---onPause: " );
}
@Override
protected void onStop() {
super.onStop();
Log.e(TAG, "singleTop---onStop: " );
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e(TAG, "singleTop---onDestroy: " );
}
public void intoSingleTop(View view) {
Intent intent = new Intent(this, SingleTopActivity.class);
startActivity(intent);
}
public void intoOtherTop(View view) {
Intent intent = new Intent(this, OtherTopActivity.class);
startActivity(intent);
}
}
测试结果:
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 重新创建了.
总结:
- 当前栈中已有该Activity的实例并且该实例位于栈顶时,不会新建实例,而是复用栈顶的实例,并且会将Intent对象传入,回调onNewIntent方法
- 当前栈中已有该Activity的实例但是该实例不在栈顶时,其行为和standard启动模式一样,依然会创建一个新的实例
- 当前栈中不存在该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:
public class SingleTaskActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_task);
}
public void intoSingleTask(View view) {
Intent intent = new Intent(this, SingleTaskActivity.class);
startActivity(intent);
}
public void intoOtherSingleTask(View view) {
Intent intent = new Intent(this, OtherSingleTaskActivity.class);
startActivity(intent);
}
}
总结:
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:
public class SingleInstanceActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_instance);
}
public void goToStanard(View view) {
startActivity(new Intent(this,OtherSingleInstanceActivity.class));
}
}
测试:
- 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 界面. - 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 界面, 再回退退出. - 从别的应用进入
- 在 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 - 先创建 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 没有创建时, 直接在另一个应用进入
我们看到,第一个应用启动SingleInstanceActivity时,由于系统中不存在该实例,所以新建了一个Task,按home键后,使用另一个App进入该Activity,由于系统中已经存在了一个实例,不会再创建新的Task,直接复用该实例,并且回调onNewIntent方法。可以从他们的hashcode中可以看出这是同一个实例。因此我们可以理解为:SingleInstance模式启动的Activity在系统中具有全局唯一性。