启动模式允许开发者定义一个activity的新实例如何与当前的Task关联。
1,在Manifest.xml文件声明activity时指定启动模式:
<activity android:name=".MainActivity" android:launchMode="standard" />
1. standard 默认启动模式,每次激活Activity时都会创建Activity,并放入任务栈中。
2. singleTop 如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,否者就会创建新的实例并放入栈顶(即 使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。
3. singleTask 如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让 该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。
4. singleInstance 在一个新栈中创建该Activity实例,并让多个应用共享改栈中的该Activity实例。一旦改模式的 Activity的实例存在于某个栈中,任何应用再激活改Activity时都会重用该栈中的实例,其效果相当于多个应用程序共 享一个应用,不管谁激活该Activity都会进入同一个应用中。
几种模式的区别体现以下四点上:
1)当这个activity被激活的时候,会放入哪个任务栈。
对于“standard”和“singleTop”模式,这个新被激活的activity会放入和之前的activity相同的任务栈中――除非Intent对象包含FLAG_ACTIVITY_NEW_TASK标志。
“singleTask”并不会每次都新启动一个task。如果已经存在一个task与新activity亲和度(taskAffinity)一样,则activity将启动到该task。如果不是,才启动一个新task。同一个application里面,每个activity的taskAffinity默认都是一样的。
singleInstance”模式则表示这个新被激活的activity会重新开启一个任务栈,并作为这个新的任务栈的唯一的activity。
2)是否可以存在这个activity类型的多个实例。
对于“standard”和“singleTop”模式,可以有多个实例,并且这些实例可以属于不同的任务栈,每个任务栈也可以包含有这个activity类型的多个实例。
“singleTop"要求如果创建intent的时候栈顶已经有要创建 的Activity的实例,则将intent发送给该实例,而不发送给新的实例。
“singleTask”和”singleInstance”则限制只生成一个实例。
3)包含此activity的任务栈是否可以包含其它的activity。
“singleInstance”模式表示包含此activity的任务栈不可以包含其它的activity。若此activity启动了另一个activity组件,那么无论那个activity组件的启动模式是什么或是Intent对象中是否包含了FLAG_ACTIVITY_NEW_TASK标志,它都会被放入另外的任务栈。在其它方面“singleInstance”模式和“singleTask”模式是一样的。
其余三种启动模式则允许包含此activity的任务栈包含其它的activity。
4)是否每次都生成新实例
对于默认的“standard”模式,每当响应一个Intent对象,都会创建一个这种activity类型的新的实例。即每一个activity实例处理一个intent。
对于“singleTop”模式,只有当这个activity的实例当前处于任务栈的栈顶位置,则它会被重复利用来处理新到达的intent对象。否则就和“standard”模式的行为一样。
“singleInstance”是其所在栈的唯一activity,它会每次都被重用。
对于“singleTask”模式的acitvity,在其上面可能存在其它的activity组件,所以它的位置并不是栈顶,在这种情况下,intent对象会被丢弃。(虽然会被丢弃,但是这个intent对象会使这个任务栈切换到前台)
注意:当已经存在的activity实例处理新的intent时候,会调用onNewIntent()方法
若为了处理一个新到达的intent对象而创建了一个activity实例,则用户按下“BACK”键就会退到之前的那个activity。但若这个新到达的intent对象是由一个已经存在的activity组件来处理的,那么用户按下“BACK” 键就不会回退到处理这个新intent对象之前的状态了。
2.通过在intent中包含标志来修改activity的默认的与当前task的关联,然后将该intent传递给startActivity()可以修改的默认的标志:
FLAG_ACTIVITY_NEW_TASK 在一个新的task中开启一个activity。如果包含该activity的task已经运行,该task就回到前台,activity通过onNewIntent()接受处理该intent。这是与"singleTask"登录模式相同的行为。
FLAG_ACTIVITY_SINGLE_TOP 如果要被开启的activity是当前的activity(在返回栈的顶部),已经存在的实例通过onNewIntent()接收一个调用,然后处理该intent,而非重新创建一个新的实例。这与"singleTop"登录模式有相同的行为。
FLAG_ACTIVITY_CLEAR_TOP 如果要被开启的activity已经在当前的task中运行,系统不会生成该activity的一个新的实例,在该栈顶部的所有其他的activity会被销毁,这个intent通过 onNewIntent()被传递给该重新运行的activity的实例(现在在栈顶部)。manifest中没有相对应的属性。
FLAG_ACTIVITY_CLEAR_TOP经常和FLAG_ACTIVITY_NEW_TASK一起使用。当一起使用时,这些标志可以确定一个存在的activity在另一个task中的位置,并且将其放置于可以响应intent的位置(FLAG_ACTIVITY_NEW_TASK确定该activity,然后FLAG_ACTIVITY_CLEAR_TOP销毁顶部其他的activity)。如果指定的activity的登录模式是"standard",也会被从栈中移除,一个新的实例也会被登录到它的位置来处理到来的intent。那是因为当登录模式为 "standard"时,一个新的实例总是被创建
注意: 其实以上的解释一起用非常复杂,比如一般系统默认activity是 standard,但当我activity代码设置为FLAG_ACTIVITY_NEW_TASK时仍然还是生成新的activity,当设置FLAG_ACTIVITY_CLEAR_TOP 时也是生成新的activity,当FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK时也是生成新的activity,或许这句好是经典“登录模式为 "standard"时,一个新的实例总是被创建”。
关于singleTask启动模式下onNewIntent()调用详细说明:
默认情况下通过Intent启动Activity的时,就算已经存在相同的正在运行的Activity,系统都会创建一个新的Activity实例并显示出来。为了不让Activity实例化多次,可以在AndroidManifest.xml配置activity的加载方式(launchMode)实现单任务模式:<activity android:label="@string/app_name" android:launchmode="singleTask"android:name="Activity1"/>
当launchMode为singleTask时,通过Intent启动Activity,如果系统中已经存在一个实例,系统就会将请求直接发送到这个实例上,这时Activity处于onPause、onStop 状态,不会再执行 onCreate 方法,而是从onNewIntent方法开始 ,此时需要把数据处理的代码写到 onNewInten方法中:protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);//must store the new intent unless getIntent() will return the old one
processExtraData();
}
但系统随时
可能会
杀掉后台运行的Activity,如果被杀或者第一次启动的情况下,
Activity
还是
会从onCreate方法开始
,并且不会
调用onNewIntent方法了,所以最好在在onCreate和onNewIntent方法中都一下处理数据的方法:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
processExtraData();
}
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);//需要自己设置must store the new intent unless getIntent() will return the old one
processExtraData()
}
private void processExtraData(){
Intent intent = getIntent();
//use the data received here
}