Activity启动模式之SingleTask

Android本身的activity启动模式分为四种standardsingleTopsingleTasksingleInstance。由于标准启动模式和singleTop比较简单,所以不再记录。接下来就看看singleTask

首先要知道Android的task可以看成是一个栈,first in,last out。
官网对singleTask的定义如下:

The system creates a new task and instantiates the activity at the root of the new task. However, if an instance of the activity already exists in a separate task, the system routes the intent to the existing instance through a call to its onNewIntent() method, rather than creating a new instance. Only one instance of the activity can exist at a time.

大意是系统创建一个新的task并且在新的task栈底实例化这个activity。然而如果这个activity的一个实例已经存在于一个单独的task栈中,系统会通过调用onNewIntent()把intent关联到已经存在的activity实例。每次只能存在一个activity的实例。

好像说的不是很清楚,接下来举例说明一下:
首先创建两个activity,activity a和b。

ActivityA代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a);
TextView tv = (TextView) findViewById(R.id.text);
tv.setText(this.toString() + "--" + this.getTaskId());
}
//页面上按钮点击跳转activity
public void go(View v){
Intent intent = new Intent(this, ActivityB.class);
startActivity(intent);
}

ActivityB代码如下:

1
2
3
4
5
6
7
8
9
10
11
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
TextView tv = (TextView) findViewById(R.id.text);
tv.setText(this.toString() + "--" + this.getTaskId());
}
public void go(View v){
Intent intent = new Intent(this, ActivityA.class);
startActivity(intent);
}

上面的代码除了布局和启动的activity不一样外没有区别。

布局文件(两个布局文件一样):

1
2
3
4
5
6
7
8
9
10
11
12
<LinearLayout ...>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:onClick="go"/>
</LinearLayout>

manifest文件配置:

1
2
3
4
5
6
7
8
9
10
11
12
<application >
<activity
android:name=".ActivityA"
android:launchMode="singleTask" ><!-- 配置activity a -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="ActivityB" >
</activity>
</application>

上面的例子是把activity a设置为singleTask,这时从A启动B,再从B启动A,然后按返回按钮,直到退出app。如果没有设置启动模式的话,这时会按照A->B->A->退出app。而设置了singleTask之后,这时按返回按钮会直接退出app。这时因为设置了singleTask的activity当再次被调用的时候会把栈中在它上面的activity出栈然后这个activity成为栈顶,如果再次调用时此activity已处于栈顶的话则不会对其他activity产生影响。

如下图:

当B启动A时就已经变为右图的样子A之前的activity全部出栈,在本例中task栈中只有A一个activity,所以再按返回键时就会退出app。如果要描述的更准确点的话左边的栈是不设置singleTask时栈的状态,右图是设置singleTask后栈的状态。

更换条件

此时我们把ActivityA设置为标准启动模式,把ActivityB设置为singleTask。然后我们从A启动B,再从B启动A。接下来再按返回键。这时程序的退出顺序会和没有设置启动模式时一样都是A->B->A->退出app。因为这时并没有再次调用B,所以singleTask实际上并没有显示效果。我们应该按照A->B->A->B这样的顺序启动activity,然后再按返回键才能看到效果。因为再次调用B的时候B并不在task栈的栈顶,所以会把B之前的A出栈。所以退出的顺序变为B->A->退出app。

如下图:

上图的结果再次证明了每次重新调用启动模式为singleTask的activity时,此activity的实例会把它上面的activity实例全部出栈,然后此activity置顶。