啓動模式(launchMode) 在多個 Activity 跳轉的過程中扮演着重要的角色, 它可以決定是否生成新的 Activity 實例,
是否重用已存在的 Activity 實例,是否和其他 Activity 實例公用一個 task 裏。這裏簡單介紹一下 task 的概念,task 是
一個具有棧結構的對象,一個 task 可以管理多個 Activity,啓動一個應用,也就創建一個與之對應的 task。
Activity 一共有以下四種 launchMode:
1.standard
2.singleTop
3.singleTask
4.singleInstance
我們可以在 AndroidManifest.xml 配置<activity>的 android:launchMode 屬性爲以上四種之一即可。
下面我們結合實例一一介紹這四種 lanchMode:
1
standard
standard 模式是默認的啓動模式,不用爲<activity>配置 android:launchMode 屬性即可,當然也可以指定值
爲 standard。
我們將創建一個 Activity,命名爲 FirstActivity,來演示一下標準的啓動模式。FirstActivity 代碼如下:
public class FirstActivity extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first);
TextView textView = (TextView) findViewById(R.id.tv);
textView.setText(this.toString());
Button button = (Button) findViewById(R.id.bt);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,
FirstActivity.class);
startActivity(intent);
}
});
}
}
FirstActivity 界面中的 TextView 用於顯示當前 Activity 實例的序列號, Button 用於跳轉到下一個 FirstActivity 界面。
然後我們連續點擊幾次按鈕,將會出現下面的現象:
我們注意到都是
FirstActivity 的實例, 但序列號不同, 並且我們需要連續按後退鍵兩次, 才能回到第一個 FirstActivity。
standard 模式的原理如下圖所示:
如圖所示,每次跳轉系統都會在 task 中生成一個新的 FirstActivity 實例,並且放於棧結構的頂部,當我們按下後退鍵
時,才能看到原來的 FirstActivity 實例。
這就是 standard 啓動模式,不管有沒有已存在的實例,都生成新的實例。
2
singleTop
我們在上面的基礎上爲<activity>指定屬性 android:launchMode="singleTop",系統就會按照 singleTop 啓
動模式處理跳轉行爲。我們重複上面幾個動作,將會出現下面的現象:
我們看到這個結果跟 standard 有所不同,三個序列號是相同的,也就是說使用的都是同一個 FirstActivity 實例;
如果按一下後退鍵,程序立即退出,說明當前棧結構中只有一個 Activity 實例。singleTop 模式的原理如下圖所示:
正如上圖所示,跳轉時系統會先在棧結構中尋找是否有一個 FirstActivity 實例正位於棧頂,如果有則不再生成新的,
而是直接使用。也許朋友們會有疑問,我只看到棧內只有一個 Activity,如果是多個 Activity 怎麼辦,如果不是在棧
頂會如何?我們接下來再通過一個示例來證實一下大家的疑問。
我們再新建一個 Activity 命名爲 SecondActivity,如下:
public class SecondActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second);
TextView textView = (TextView) findViewById(R.id.tv);
textView.setText(this.toString());
Button button = (Button) findViewById(R.id.button);
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.clas
s);
startActivity(intent);
這時候,FirstActivity 會跳轉到 SecondActivity,SecondActivity 又會跳轉到 FirstActivity。演示結果如下:
我們看到,兩個 FirstActivity 的序列號是不同的,證明從 SecondActivity 跳轉到 FirstActivity 時生成了新的
FirstActivity 實例。原理圖如下:
我們看到,當從 SecondActivity 跳轉到 FirstActivity 時,系統發現存在有 FirstActivity 實例,但不是位於棧頂,
於是重新生成一個實例。
這就是 singleTop 啓動模式,如果發現有對應的 Activity 實例正位於棧頂,則重複利用,不再生成新的實例。
3
singleTask
在上面的基礎上我們修改 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
這種啓動模式比較特殊,因爲它會啓用一個新的棧結構,將 Activity 放置於這個新的棧結構中,並保證不再有其
他 Activity 實例進入。
我們修改 FirstActivity 的 launchMode="standard",SecondActivity 的 launchMode="singleInstance",由
於涉及到了多個棧結構,我們需要在每個 Activity 中顯示當前棧結構的 id,所以我們爲每個 Activity 添加如下代碼:
TextView taskIdView = (TextView) findViewById(R.id.taskIdView);
taskIdView.setText("current task id: " + this.getTaskId());
然後我們再演示一下這個流程:
我們發現這兩個 Activity 實例分別被放置在不同的棧結構中,關於 singleInstance 的原理圖如下
我們看到從 FirstActivity 跳轉到 SecondActivity 時,重新啓用了一個新的棧結構,來放置 SecondActivity 實例,
然後按下後退鍵,再次回到原始棧結構;圖中下半部分顯示的在 SecondActivity 中再次跳轉到 FirstActivity,這個時
候系統會在原始棧結構中生成一個 FirstActivity 實例, 然後回退兩次, 注意, 並沒有退出, 而是回到了 SecondActivity,
爲什麼呢?是因爲從 SecondActivity 跳轉到 FirstActivity 的時候,我們的起點變成了 SecondActivity 實例所在的棧
結構,這樣一來,我們需要“迴歸”到這個棧結構。
如果我們修改 FirstActivity 的 launchMode 值爲 singleTop、singleTask、singleInstance 中的任意一個,流程將會
如圖所示: