launchMode在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例公用一个task
里。这里简单介绍一下task
的概念,task
是一个具有栈(后进先出)结构的对象,一个task
可以管理多个Activity,启动一个应用,也就创建一个与之对应的task
。
Activity一共有以下四种LaunchMode:
1.standard
2.singleTop
3.singleTask
4.singleInstance
我们可以在AndroidManifest.xml
配置
的Android: LaunchMode属性为以上四种之一即可,如果不配置,默认是standard
。
1、standard
:标准模式,这也是系统的默认模式。每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。被创建的实例的生命周期符合典型情况下的生命周期,它的onCreate
、onStart
、onResume
都会被调用。该模式不会调用onNewIntent
方法。
下面用一个例子演示一下standard
模式:
public class FirstActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(this.toString());
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,FirstActivity.class);
startActivity(intent);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.i("FirstActivity","onNewIntent called");}
});
}
}
通过图片可以看到,我们每次点击按钮都新建了不同的FirstActivity实例,并且我们需要连续按后退键两次,才能回到第一个FristActivity。
standard
模式的原理如下图所示:
如图所示,每次跳转系统都会在
task
中生成一个新的FirstActivity实例,并且放于栈结构的顶部,当我们按下后退键时,才能看到原来的FirstActivity实例。
这就是
standard
启动模式,不管栈有没有已存在的实例,都会创建新的实例。
2、
singleTop
:栈顶复用模式。在这种模式下,1️⃣如果新的Activity已经位于任务栈的
栈顶,注意是位于栈顶,那么此Activity不会被重新创建,同时它的
onNewIntent
方法会被调用,通过此方法的参数我们可以取出当前请求的信息。需要注意的是,
onCreate
、
onStart
、
onResume
不会被调用,因为它并没有发生改变。2️⃣但是如果新的Activity实例
已存在但没有位于栈顶,那么新的Activity仍然会被重新创建。
1️⃣
我们在上面代码的基础上为
android:launchMode="singleTop"
,系统就会按照
singleTop
启动模式处理跳转行为。我们重复上面几个动作,将会出现下面的现象:
同时
onNewIntent
会被调用,我们可以在
onNewIntent
中的形参
Intent intent
获取一些数据做一些操作。
09-19 17:51:27.013 6674-6674/xiaoyong68.com.activitylaunchmode I/FirstActivity: onNewIntent called
我们看到这个结果跟standard有所不同,三个序列号是相同的,也就是说使用的都是同一个FirstActivity实例;如果按一下后退键,程序立即退出,说明当前栈结构中只有一个Activity实例。
singleTop模式的原理如下图所示:
正如上图所示,跳转时系统会先在栈结构中寻找是否有一个FirstActivity实例正位于栈顶,如果有则不再生成新的,而是直接使用。也许朋友们会有疑问,我只看到栈内只有一个Activity,如果是多个Activity怎么办,如果不是在栈顶会如何?2️⃣我们接下来再通过一个示例来证实一下大家的疑问。
我们再新建一个Activity命名为SecondActivity,如下:
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(this.toString());
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
startActivity(intent);
}
});
}
}
然后将FirstActivity中的跳转代码改为:
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
点击FirstActivity中按钮会从FirstActivity跳转到SecondActivity,点击SecondActivity中按钮会从SecondActivity又会跳转到FirstActivity。演示结果如下:
我们看到,两个FirstActivity的序列号是不同的,证明从SecondActivity跳转到FirstActivity时生成了新的FirstActivity实例。原理图如下:
我们看到,当从SecondActivity跳转到FirstActivity时,系统发现存在有FirstActivity实例,但不是位于栈顶,于是重新生成一个实例,这种方式会重新新建,
onCreate
、
onStart
、
onResume
会被调用,但是
onNewIntent
则不会被调用。
值得注意的是,当我们不按SecondAndroid的按钮而直接按back键返回到FirstActivity时,FirstActivity不会重新创建,只是把原来的重新展现,生命周期函数执行如下:onRestart
->onStart
->onResume
->onWindowFocusChanged
09-19 20:31:19.914 14458-14458/xiaoyong68.com.activitylaunchmode I/FirstActivity: onRestart called.
09-19 20:31:19.918 14458-14458/xiaoyong68.com.activitylaunchmode I/FirstActivity: onStart called.
09-19 20:31:19.918 14458-14458/xiaoyong68.com.activitylaunchmode I/FirstActivity: onResume called.
09-19 20:31:19.978 14458-14458/xiaoyong68.com.activitylaunchmode I/FirstActivity: onWindowFocusChanged called.
这就是singleTop启动模式,如果发现有对应的Activity实例正位于栈顶,则重复利用,不再生成新的实例。
3、
singleTask
:栈内复用模式。这是一种单实例模式,在这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,系统会回调其onNewIntent
方法。具体一点,当一个具有singleTask
模式的Activity请求启动后,例如Activity A,系统首先会寻找是否存在A想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建A的实例后把A放到栈中。如果存在A所需要的任务栈,这时需要看A是否在栈中有实例存在,如果有,那么系统就把A调到(在A前面的Activity实例全部出栈)栈顶并调用其onNewIntent
方法,如果不存在实例,就创建A的实例并把A压入栈中。
在上面的基础上我们修改FirstActivity的属性android:launchMode="singleTask"
。演示的结果如下:
我们注意到,在上面的过程中,FirstActivity的序列号是不变的,SecondActivity的序列号却不是唯一的,说明从SecondActivity跳转到FirstActivity时,没有生成新的实例,但是从FirstActivity跳转到SecondActivity时生成了新的实例。singleTask模式的原理图如下图所示:
在图中的下半部分是SecondActivity跳转到FirstActivity后的栈结构变化的结果,我们注意到,SecondActivity消失了,没错,在这个跳转过程中系统发现有存在的FirstActivity实例,于是不再生成新的实例,而是将FirstActivity之上的Activity实例统统出栈,将FirstActivity变为栈顶对象,显示到幕前。也许朋友们有疑问,如果将SecondActivity也设置为singleTask模式,那么SecondActivity实例是不是可以唯一呢?在我们这个示例中是不可能的,因为每次从SecondActivity跳转到FirstActivity时,SecondActivity实例都被迫出栈,下次等FirstActivity跳转到SecondActivity时,找不到存在的SecondActivity实例,于是必须生成新的实例。但是如果我们有ThirdActivity,让SecondActivity和ThirdActivity互相跳转,那么SecondActivity实例就可以保证唯一。
这就是singleTask模式,如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。
4、
singleInstance
:单实例模式。是一种加强的
singleTask
模式,它除了具有
singleTask
模式的所有特性外,还加强了一点,那就是此种模式的Activity只能单独地位于一个任务栈中,换句话说,比如Activity A是
singleInstance
模式,当A启动后,系统会为它创建一个新的任务栈,然后A独自在这个新的任务栈中,由于栈内复用的特性,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了。