Activity四種啓動模式

今天問我Activity啓動模式有幾種,當時我沒有答出來。html

我把standard模式說成了,default模式。(⊙﹏⊙)android

由於我通常都不會記這種東西,由於百度一收有不少資料。也比較簡單。git

今天忽然問,想不起來了。從新回顧一下:app

參考:http://www.cnblogs.com/lwbqqyumidi/p/3771542.htmlide

launchMode在多個Activity跳轉的過程當中扮演着重要的角色,它能夠決定是否生成新的Activity實例,是否重用已存在的Activity實例,是否和其餘Activity實例公用一個task裏。這裏簡單介紹一下task的概念,task是一個具備棧結構的對象,一個task能夠管理多個Activity,啓動一個應用,也就建立一個與之對應的task。post

Activity一共有如下四種launchMode:this

1.standardspa

2.singleTopcode

3.singleTaskorm

4.singleInstance

咱們能夠在AndroidManifest.xml配置<activity>的android:launchMode屬性爲以上四種之一便可。

下面咱們結合實例一一介紹這四種lanchMode:

1.standard

standard模式是默認的啓動模式,不用爲<activity>配置android:launchMode屬性便可,固然也能夠指定值爲standard。

咱們將會一個Activity,命名爲FirstActivity,來演示一下標準的啓動模式。FirstActivity代碼以下:

複製代碼
 1 package com.scott.launchmode;
 2 
 3 import android.app.Activity;
 4 import android.content.Intent;
 5 import android.os.Bundle;
 6 import android.view.View;
 7 import android.widget.Button;
 8 import android.widget.TextView;
 9 
10 public class FirstActivity extends Activity {
11     @Override
12     public void onCreate(Bundle savedInstanceState) {
13         super.onCreate(savedInstanceState);
14         setContentView(R.layout.first);
15         TextView textView = (TextView) findViewById(R.id.textView);
16         textView.setText(this.toString());
17         Button button = (Button) findViewById(R.id.button);
18         button.setOnClickListener(new View.OnClickListener() {
19             @Override
20             public void onClick(View v) {
21                 Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
22                 startActivity(intent);
23             }
24         });
25     }
26 }
複製代碼

咱們FirstActivity界面中的TextView用於顯示當前Activity實例的序列號,Button用於跳轉到下一個FirstActivity界面。

而後咱們連續點擊幾回按鈕,將會出現下面的現象:

咱們注意到都是FirstActivity的實例,但序列號不一樣,而且咱們須要連續按後退鍵兩次,才能回到第一個FristActivity。standard模式的原理以下圖所示:

如圖所示,每次跳轉系統都會在task中生成一個新的FirstActivity實例,而且放於棧結構的頂部,當咱們按下後退鍵時,才能看到原來的FirstActivity實例。

這就是standard啓動模式,無論有沒有已存在的實例,都生成新的實例。

簡單點理解:standard啓動模式Activity棧從棧底到棧頂順序爲A1 -> B -> C -> A2...。(其中A、B、C等都表示不一樣的Activity實例,A一、A2則表示屬於具備同一Activity類的不一樣實例)

 

2.singleTop

咱們在上面的基礎上爲<activity>指定屬性android:launchMode="singleTop",系統就會按照singleTop啓動模式處理跳轉行爲。咱們重複上面幾個動做,將會出現下面的現象:

咱們看到這個結果跟standard有所不一樣,三個序列號是相同的,也就是說使用的都是同一個FirstActivity實例;若是按一下後退鍵,程序當即退出,說明當前棧結構中只有一個Activity實例。singleTop模式的原理以下圖所示:

正如上圖所示,跳轉時系統會先在棧結構中尋找是否有一個FirstActivity實例正位於棧頂,若是有則再也不生成新的,而是直接使用。也許朋友們會有疑問,我只看到棧內只有一個Activity,若是是多個Activity怎麼辦,若是不是在棧頂會如何?咱們接下來再經過一個示例來證明一下你們的疑問。

咱們再新建一個Activity命名爲SecondActivity,以下:

複製代碼
 1 package com.scott.launchmode;
 2 
 3 import android.app.Activity;
 4 import android.content.Intent;
 5 import android.os.Bundle;
 6 import android.view.View;
 7 import android.widget.Button;
 8 import android.widget.TextView;
 9 
10 public class SecondActivity extends Activity {
11     @Override
12     protected void onCreate(Bundle savedInstanceState) {
13         super.onCreate(savedInstanceState);
14         setContentView(R.layout.second);
15         TextView textView = (TextView) findViewById(R.id.textView);
16         textView.setText(this.toString());
17         Button button = (Button) findViewById(R.id.button);
18         button.setOnClickListener(new View.OnClickListener() {
19             @Override
20             public void onClick(View v) {
21                 Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
22                 startActivity(intent);                
23             }
24         });
25     }
26 }
複製代碼

而後將以前的FirstActivity跳轉代碼改成:

1 Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
2 startActivity(intent);

是的,FirstActivity會跳轉到SecondActivity,SecondActivity又會跳轉到FirstActivity。演示結果以下:

 

咱們看到,兩個FirstActivity的序列號是不一樣的,證實從SecondActivity跳轉到FirstActivity時生成了新的FirstActivity實例。原理圖以下:

咱們看到,當從SecondActivity跳轉到FirstActivity時,系統發現存在有FirstActivity實例,但不是位於棧頂,因而從新生成一個實例。

這就是singleTop啓動模式,若是發現有對應的Activity實例正位於棧頂,則重複利用,再也不生成新的實例。

簡單點理解,singleTop即表示當前Activity棧中「棧頂惟一」,Activity跳轉順序或standard模式下棧結構若是爲:A -> B -> C -> D1 -> D2,則singleTop啓動模式爲:A -> B -> C -> D1(此時回調D1的onNewIntent()..)

 

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實例通通出棧,使此Activity實例成爲棧頂對象,顯示到幕前。

簡單點理解,singleTask表示當前Activity棧中「實例惟一」,Activity跳轉順序或standard模式下棧結構若是爲:A -> B1 -> C -> D -> B2,則singleTask啓動模式爲:A -> B1(此時回調onNewIntent()..)

 

4.singleInstance

這種啓動模式比較特殊,由於它會啓用一個新的棧結構,將Acitvity放置於這個新的棧結構中,並保證再也不有其餘Activity實例進入。

咱們修改FirstActivity的launchMode="standard",SecondActivity的launchMode="singleInstance",因爲涉及到了多個棧結構,咱們須要在每一個Activity中顯示當前棧結構的id,因此咱們爲每一個Activity添加以下代碼:

1 TextView taskIdView = (TextView) findViewById(R.id.taskIdView);
2 taskIdView.setText("current task id: " + this.getTaskId());

而後咱們再演示一下這個流程:

 

咱們發現這兩個Activity實例分別被放置在不一樣的棧結構中,關於singleInstance的原理圖以下:

咱們看到從FirstActivity跳轉到SecondActivity時,從新啓用了一個新的棧結構,來放置SecondActivity實例,而後按下後退鍵,再次回到原始棧結構;圖中下半部分顯示的在SecondActivity中再次跳轉到FirstActivity,這個時候系統會在原始棧結構中生成一個FirstActivity實例,而後回退兩次,注意,並無退出,而是回到了SecondActivity,爲何呢?是由於從SecondActivity跳轉到FirstActivity的時候,咱們的起點變成了SecondActivity實例所在的棧結構,這樣一來,咱們須要「迴歸」到這個棧結構。

此處的解釋不是很贊同,第一次按Back鍵首先是在當前Activity棧中將棧頂元素出棧,而後顯示當前Activity棧中下一個Activity棧,這個沒什麼解釋的,而後按下Back鍵,不是回到手機桌面,而是回到另外一個Activity棧中的SecondActivityInstance,我認爲緣由在於在於「最近棧」,只要此棧位於上次Home操做以後,就會先顯示它。

若是咱們修改FirstActivity的launchMode值爲singleTop、singleTask、singleInstance中的任意一個,流程將會如圖所示:

singleInstance啓動模式多是最複雜的一種模式,爲了幫助你們理解,我舉一個例子,假如咱們有一個share應用,其中的ShareActivity是入口Activity,也是可供其餘應用調用的Activity,咱們把這個Activity的啓動模式設置爲singleInstance,而後在其餘應用中調用。咱們編輯ShareActivity的配置:

複製代碼
<activity android:name=".ShareActivity" android:launchMode="singleInstance">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SINGLE_INSTANCE_SHARE" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
複製代碼

而後咱們在其餘應用中這樣啓動該Activity:

1 Intent intent = new Intent("android.intent.action.SINGLE_INSTANCE_SHARE");
2 startActivity(intent);

當咱們打開ShareActivity後再按後退鍵回到原來界面時,ShareActivity作爲一個獨立的個體存在,若是這時咱們打開share應用,無需建立新的ShareActivity實例便可看到結果,由於系統會自動查找,存在則直接利用。你們能夠在ShareActivity中打印一下taskId,看看效果。關於這個過程,原理圖以下:

 

原做者此處的解釋可能有點讓人誤解。當咱們打開ShareActivity後再按後退鍵回到原來界面時,ShareActivity作爲一個獨立的個體存在,此處不該該是按Back鍵,而是Home鍵,由於一旦按下了Back鍵,ShrareActivityInstance天然就銷燬了,也就不存在所謂的「無須從新建立了」。按下Home鍵後,接下來打開app MainActivity,在另外一個Activity棧中app MainActivity入棧,此時startActivity到ShareActivity,無需建立新的ShareActivity實例便可看到結果,由於系統會自動查找,存在則直接利用。此時第一次按下Back,ShareActivity Instance出棧,此時這個棧中沒有其餘Activity了,天然是回到了app MainActivity所在的棧並顯示app MainActivity,接下來按Back鍵,此時app MainActivity所在的棧也沒有其餘Activity了,同時又不包含任何其餘的「最近棧」,天然是回到了手機桌面。注:此處理解的「最近棧」是以Home鍵或桌面狀態爲間隔區分。

簡單點理解,singleInstance所標識的Activity,當被啓動時,系統會首先判斷系統其餘棧中是否已經存在此Activity實例,有則直接使用,而且其所在的Activity棧理論上只有它一個Activity元素。因此啓動它的Activity與它並不在一個task中,因此才須要特別注意Back的問題。通常表示爲:task1 A -> task2 B。

singleInstance表示該Activity在系統範圍內「實例惟一」。由此咱們發現,singInstance和singleTask主要區別在與系統範圍內的「實例惟一」仍是當前Activity棧「實例惟一」。

 

--------------------------------------------------------------------------------- 
筆者水平有限,如有錯漏,歡迎指正,若是轉載以及CV操做,請務必註明出處,謝謝!
 
分類:  Android
 
好文要頂  關注我  收藏該文 
4
0
 
 
 
« 上一篇: Android總結篇系列:Activity生命週期
» 下一篇: Android總結篇系列:Activity Intent Flags及Task相關屬性
posted @  2014-06-07 19:09 Windstep 閱讀(15405) 評論(0) 編輯 收藏
相關文章
相關標籤/搜索