Android的Activity一共有四种launchMode:standard、singleTop、singleTask、singleInstance,在AndroidManifest.xml中用来指定Activity的启动方式。
一、standard
activity的默认启动方式,未指定android:launchMode的属性时默认为standard。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("", "MainActivity: " + this.toString());
findViewById(R.id.start_new_activity).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, MainActivity.class));
}
});
}
}
三次点击start_new_activity,结果如下:
MainActivity: com.example.liuwei.myapplication.MainActivity@43090380
MainActivity: com.example.liuwei.myapplication.MainActivity@430aac80
MainActivity: com.example.liuwei.myapplication.MainActivity@430b67f0
MainActivity: com.example.liuwei.myapplication.MainActivity@430c1ab8
可以发现,同样的MainActivity创建了四个不同的实例,点击四次返回键,才可以退出整个APP。
standard启动模式中,不管有没有已经存在的实例,都会创建一个新的实例。
二、singleTop
指定launchMode为singleTop,重复执行上述操作,结果如下:
MainActivity: com.example.myapp.MainActivity@3c8362e9
同时APP并没有出现activity之间跳转的现象,点击返回键直接退出当前APP,说明当指定为singleTop时,栈中只有一个MainActivity的实例。在MainActivity中重写onNewIntent()方法,发现点击按钮时都会调用一次onNewIntent()方法。
创建一个新的Activity,执行其launchMode为singleTop。让MainActivity和AnotherActivity互相跳转。
代码如下:
public class AnotherActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("111111111111111", "AnotherActivity: " + this.toString());
findViewById(R.id.start_new_activity).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(AnotherActivity.this,
MainActivity.class));
}
});
}
@Override
protected void onNewIntent(Intent intent) {
// TODO Auto-generated method stub
super.onNewIntent(intent);
Log.e("111111111111", "onNewIntent()");
}
}
执行APP,点击跳转按钮,结果如下:
MainActivity: com.example.myapp.MainActivity@beaa115
AnotherActivity: com.example.myapp.AnotherActivity@2ceddcd
MainActivity: com.example.myapp.MainActivity@19f6f985
AnotherActivity: com.example.myapp.AnotherActivity@3c1fd43d
MainActivity: com.example.myapp.MainActivity@12c24df5
AnotherActivity: com.example.myapp.AnotherActivity@219346ad
在互相跳转的过程中,MainActivity和AnotherActivity每次都会创建一个新的实例,而没有使用原有的实例。
当launchMode指定为singleTop时,如果要启动的Activity正处于栈的顶端,则重复利用原有的Activity,不再创建新的实例。
三、singleTask
指定MainActivity和AnotherActivity的launchMode均为singleTask。
重复之前的操作,结果如下:
MainActivity: com.example.liuwei.myapplication.MainActivity@430902d0
AnotherActivity: com.example.liuwei.myapplication.AnotherActivity@430aae90
MainActivity:onNewIntent()
AnotherActivity: com.example.liuwei.myapplication.AnotherActivity@430b7d30
MainActivity:onNewIntent()
AnotherActivity: com.example.liuwei.myapplication.AnotherActivity@430c3bc0
MainActivity的实例只会创建一次,之后都是重用之前的实例,而AnotherActivity每次都会创建新的实例。
过程如下:
- 第一次创建一个MainActivity的实例;
- 然后创建一个AnotherActivity的实例;
- 再次进入MainActivity时,已经存在实例,直接使用,但是这时候会将栈顶MainActivity实例之后的所有activity出栈;
再次进入AnotherActivity时,已经找不到AnotherActivity的实例,无法复用,只能创建一个新的AnotherActivity的实例了。
在singleTask模式中,如果发现已经有activity的实例,则复用该实例,但此实例之上的其他实例都会出栈。
四、singleInstance
指定MainActivity和AnotherActivity的launchMode为singleInstance。重复之前的操作,结果如下:
MainActivity: com.example.liuwei.myapplication.MainActivity@43096180
AnotherActivity: com.example.liuwei.myapplication.AnotherActivity@430b0d80
MainActivity:onNewIntent()
AnotherActivity:onNewIntent()
MainActivity:onNewIntent()
AnotherActivity:onNewIntent()
MainActivity和AnotherActivity分别创建了一个实例,之后都是在复用之前创建的实例。点击返回键,两次就退出整个APP。
查阅资料发现,MainActivity和AnotherActivity的实例分别位于两个不同的栈中,栈中有实例的时候,直接复用实例。
指定为singleInstance的activity,创建时会进入一个新的栈并独占该栈,之后不会再创建实例,而是直接使用之前栈中的实例,除非该实例已经被销毁(比如执行了返回)。而新创建的其他activity的实例会进入到其他栈中,不会进入指定为singleInstance的activity创建的栈中。
五、onNewIntent(Intent intent)的调用时机
在上述代码中,可以看到,每次重用activity实例的时候,都会调用onNewIntent()。
重用实例的生命周期如下:
onNewIntent() –> onRestar() –> onStart() –> onResume()
注意:重用实例时如果涉及到通过Intent传递参数,那么在onNewIntent中一定执行一次setIntent(intent),否则会导致通过getInent()拿到的intent是旧数据,而不是最新的参数。
Note that getIntent() still returns the original Intent. You can use setIntent(Intent) to update it to this new Intent.