任务栈
我们都知道,每启动一个Activity时,系统会将其压入到一个任务栈中,当我们使用back键时,被返回的Activity会从任务栈中弹出,直到栈空为止。当任务栈中没有Activity时,系统会回收掉这个任务栈。
然而什么是任务栈呢?
默认情况下,所有Activity所需的任务栈的名字为应用的包名。
参数:TaskAffinity(任务相关性) :标识了一个Activity所需要的任务栈的名字。 此属性主要和singleTask配对使用。
任务栈有两种:
* 前台任务栈
* 后台任务栈 处于暂停状态
四种启动模式:
standard 标准模式(默认的模式)
每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否存在。一个任务栈可以有多个实例,每个实例可以属于不同的任务栈。
例子
现在已启动MainActivity(用Main表示),那么系统会将该Activity压入栈中。如果在MainActivity中要启动MainActivity,结果会怎样呢?我们看如下代码
<!-- launchMode属性设置Activity为标准模式 -->
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="standard" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
我们在MainActivity中启动MainActivity。代码如下
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
Button btn_launch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate()");
btn_launch = (Button) findViewById(R.id.btn_launch);
btn_launch.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MainActivity.class);
startActivity(intent);
}
});
}
}
运行结果为:
我们看到,MainActivity执行了两次onCreate()
方法 。表明不管MainActivity是否在任务栈栈顶,启动MainActivity都会重新创建一次。
singleTop 栈顶复用模式
如果新Activity位于任务栈的栈顶,那么此Activity不会被重新创建,系统会调用其onNewIntent()。如果新Activity没有位于任务栈的栈顶,那么此Activity会被重新创建并位于任务栈栈顶。
例子:
如果任务栈中有MainActivity和SecondActivity,SecondActivity位于栈顶,且SecondActivity的启动模式为singleTop。那么,现在需要启动SecondActivity,系统是否会重新创建SecondActivity呢?答案是:SecondActivity不会重新创建。
代码如下
<!-- launchMode属性设置Activity为标准模式 -->
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="standard" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- launchMode属性设置Activity为singleTop启动模式 -->
<activity
android:name=".SecondActivity"
android:label="@string/title_activity_second"
android:launchMode="singleTop"
>
</activity>
MainActivity的代码
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
Button btn_launch_second;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate()");
btn_launch_second = (Button) findViewById(R.id.btn_launch_second);
btn_launch_second.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
SecondActivity代码
public class SecondActivity extends Activity {
private static final String TAG = "SecondActivity";
Button btn_launch_third;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Log.d(TAG, "onCreate()");
btn_launch_third = (Button) findViewById(R.id.btn_launch_third);
btn_launch_third.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d(TAG, "onNewIntent()");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause()");
}
}
输出结果为:
当再次启动SecondActivity时,系统不会重新创建Activity实例,而是调用它的onNewIntent()
方法。
现在,我们考虑另外一种情况。如果MainActivity为singleTop启动模式,而SecondActivity为标准模式,且位于任务栈栈顶。当我们需要在SecondActivity中启动MainActivity时,会出现什么情况?答案是:系统会重新创建MainActivity。
只需将上面的代码中MainActivity中的启动模式改为singleTop,并在SecondActivity中启动MainActivity即可。这里就不贴代码了。
我们看以下运行结果:
MainActivity重新创建了。
singleTask 栈内复用模式
这是一种单例模式,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建。当一个具有singleTask模式的Activity请求启动后,比如SecondActivity。系统会首先检查是否存在SecondActivity所需要的任务栈,如果不存在,系统会先创建任务栈,再创建该Activity实例,并将其压入到该任务栈中。如果存在,系统会检查SecondActivity是否在任务栈中,如果不在任务栈中,则创建SecondActivity,如果在任务栈中,则不创建,并且将SecondActivity调到栈顶,调用它的onNewIntent()
方法。
例子
如果MainActivity为标准模式,SecondActivity为singleTask模式,且位于任务栈com.nxiangbo.task01的栈底,而ThirdActivity为singleTask模式,且位于任务栈com.nxiangbo.task01的栈顶。如果要在ThirdActivity中启动SecondActivity,那么,SecondActivity是否需要重新创建?很明显,答案是:不需要重新创建SecondActivity。因为SecondActivity已经处于任务栈中,系统会弹出ThirdActivity,让SecondActivity处于栈顶。
代码如下
<!-- launchMode属性设置Activity为标准模式 -->
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- taskAffinity属性可以标识任务栈的名字 -->
<!-- launchMode属性设置Activity的启动模式 -->
<activity
android:name=".SecondActivity"
android:label="@string/title_activity_second"
android:taskAffinity="com.nxiangbo.task01"
android:launchMode="singleTask"
>
</activity>
<activity
android:name=".ThirdActivity"
android:taskAffinity="com.nxiangbo.task01"
android:launchMode="singleTask"
android:label="@string/title_activity_third" >
</activity>
MainActivity代码
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
Button btn_launch_second;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate()");
btn_launch_second = (Button) findViewById(R.id.btn_launch_second);
btn_launch_second.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
}
SecondActivity代码
public class SecondActivity extends Activity {
private static final String TAG = "SecondActivity";
Button btn_launch_third;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Log.d(TAG, "onCreate()");
btn_launch_third = (Button) findViewById(R.id.btn_launch_third);
btn_launch_third.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
startActivity(intent);
}
});
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d(TAG, "onNewIntent()");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause()");
}
}
ThirdActivity代码
public class ThirdActivity extends Activity {
private static final String TAG = "ThirdActivity";
Button btn_launch_main;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
Log.d(TAG, "onCreate()");
btn_launch_main = (Button) findViewById(R.id.btn_launch_main);
btn_launch_main.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(ThirdActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause");
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d(TAG, "onNewIntent()");
}
}
输出结果为:
singleInstance 单实例模式
这是一种加强的singleTask,除了具有singleTask的特性外,此种模式只能单独的位于一个栈中。
举例:
- 如果A是singleInstance,启动A后,系统会为它创建一个新的任务栈。
我们通过阅读前面的内容,了解到可以在AndroidMenifest.xml中的Activity标签中 通过launchMode属性设置Activity的启动模式。其实,我们也可以用Intent设置标志位 来设置Activity的启动模式。
//将Activity设置为singleTask启动模式
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
两者之间的区别为
* 第二种的优先级高于第一种。
* 第一种不能为Activity设定FLAG_ACTIVITY_CLEAR_TOP标签 ;第二种无法为Activity指定singleInstance
adb shell dumpsys activity 检测Activity的任务栈
常用Activity的Flags
* FLAG_ACTIVITY_NEW_TASK ==singleTop
* FLAG_ACTIVITY_CLEAR_TOP ==singleTask
* FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 有此标记的Activity不会出现在历史Activity列表中