【Android】android launchmode(四種啓動模式)應用場景及實例

http://www.th7.cn/Program/Android/201503/405426.shtml

http://blog.csdn.net/li_wen_qi_/article/details/51135659


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屬性爲以上四種之一即可。


[1] standard 模式

     這是默認模式,每次激活Activity時都會創建Activity實例,並放入任務棧中。

[2] singleTop 模式

     如果在任務的棧頂正好存在該Activity的實例,就重用該實例( 會調用實例的 onNewIntent() ),否則就會創建新的實例並放入棧頂,即使棧中已經存在該Activity的實例,只要不在棧頂,都會創建新的實例。

[3] singleTask 模式

     如果在棧中已經有該Activity的實例,就重用該實例(會調用實例的 onNewIntent() )。重用時,會讓該實例回到棧頂,因此在它上面的實例將會被移出棧。如果棧中不存在該實例,將會創建新的實例放入棧中。

[4] singleInstance 模式

     在一個新棧中創建該Activity的實例,並讓多個應用共享該棧中的該Activity實例。一旦該模式的Activity實例已經存在於某個棧中,任何應用再激活該Activity時都會重用該棧中的實例( 會調用實例的 onNewIntent() )。其效果相當於多個應用共享一個應用,不管誰激活該 Activity 都會進入同一個應用中。



應用場景

singleTop適合接收通知啓動的內容顯示頁面。例如,某個新聞客戶端的新聞內容頁面,如果收到10個新聞推送,每次都打開一個新聞內容頁面是很煩人的。從外界可能多次跳轉到一個界面。

singleTask適合作爲程序入口點。例如瀏覽器的主界面。不管從多少個應用啓動瀏覽器,只會啓動主界面一次,其餘情況都會走onNewIntent,並且會清空主界面上面的其他頁面。之前打開過的頁面,打開之前的頁面就ok,不再新建。

singleInstance適合需要與程序分離開的頁面。例如鬧鈴提醒,將鬧鈴提醒與鬧鈴設置分離。singleInstance不要用於中間頁面,如果用於中間頁面,跳轉會有問題,比如:A -> B (singleInstance) -> C,完全退出後,在此啓動,首先打開的是B。某個應用中用到了google地圖,當退出該應用的時候,進入google地圖,還是剛纔的界面。


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

1.standard

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

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

[java] view plaincopy
  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啓動模式,不管有沒有已存在的實例,都生成新的實例。


2.singleTop

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




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


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

我們再新建一個Activity命名爲SecondActivity,如下:

[java] view plaincopy
  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跳轉代碼改爲:

[java] view plaincopy
  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實例正位於棧頂,則重複利用,不再生成新的實例。


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

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

我們修改FirstActivity的launchMode="standard",SecondActivity的launchMode="singleInstance",由於涉及到了多個棧結構,我們需要在每個Activity中顯示當前棧結構的id,所以我們爲每個Activity添加如下代碼:

[java] view plaincopy
  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實例所在的棧結構,這樣一來,我們需要“迴歸”到這個棧結構。

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

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

[html] view plaincopy
  1. <activity android:name=".ShareActivity" android:launchMode="singleInstance">  
  2.     <intent-filter>  
  3.         <action android:name="android.intent.action.MAIN" />  
  4.         <category android:name="android.intent.category.LAUNCHER" />  
  5.     </intent-filter>  
  6.     <intent-filter>  
  7.         <action android:name="android.intent.action.SINGLE_INSTANCE_SHARE" />  
  8.         <category android:name="android.intent.category.DEFAULT" />  
  9.     </intent-filter>  
  10. </activity>  
然後我們在其他應用中這樣啓動該Activity:

[java] view plaincopy
  1. Intent intent = new Intent("android.intent.action.SINGLE_INSTANCE_SHARE");  
  2. startActivity(intent);  
當我們打開ShareActivity後再按後退鍵回到原來界面時,ShareActivity做爲一個獨立的個體存在,如果這時我們打開share應用,無需創建新的ShareActivity實例即可看到結果,因爲系統會自動查找,存在則直接利用。大家可以在ShareActivity中打印一下taskId,看看效果。關於這個過程,原理圖如下:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章