天天看點

Android開發一:Activity之間跳轉的四種launchMode

原文:http://blog.csdn.net/liuhe688/article/details/6754323

合抱之木,生於毫末;九層之台,起於累土;千裡之行,始於足下。《老子》

今天在社群看到有朋友問“如何在半年内成為頂級架構師”,有網友道“關燈睡覺,不用半年的...”,的确,做夢還來的快一些。作為一個程式員,樹立遠大的目标是值得欣賞的,但不能隻去空想,要一步一步地實踐才行。成大事者,須從小事做起;萬事起于忽微,量變引起質變。

我們今天要講的是Activity的四種launchMode。

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代碼如下:

[java]  view plain copy

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

我們FirstActivity界面中的TextView用于顯示目前Activity執行個體的序列号,Button用于跳轉到下一個FirstActivity界面。

然後我們連續點選幾次按鈕,将會出現下面的現象:

Android開發一:Activity之間跳轉的四種launchMode
Android開發一:Activity之間跳轉的四種launchMode
Android開發一:Activity之間跳轉的四種launchMode

我們注意到都是FirstActivity的執行個體,但序列号不同,并且我們需要連續按後退鍵兩次,才能回到第一個FristActivity。standard模式的原理如下圖所示:

Android開發一:Activity之間跳轉的四種launchMode

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

這就是standard啟動模式,不管有沒有已存在的執行個體,都生成新的執行個體。

2.singleTop

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

Android開發一:Activity之間跳轉的四種launchMode
Android開發一:Activity之間跳轉的四種launchMode
Android開發一:Activity之間跳轉的四種launchMode

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

Android開發一:Activity之間跳轉的四種launchMode

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

我們再建立一個Activity命名為SecondActivity,如下:

[java]  view plain copy

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

然後将之前的FirstActivity跳轉代碼改為:

[java]  view plain copy

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

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

Android開發一:Activity之間跳轉的四種launchMode
Android開發一:Activity之間跳轉的四種launchMode
Android開發一:Activity之間跳轉的四種launchMode

我們看到,兩個FirstActivity的序列号是不同的,證明從SecondActivity跳轉到FirstActivity時生成了新的FirstActivity執行個體。原理圖如下:

Android開發一:Activity之間跳轉的四種launchMode

我們看到,當從SecondActivity跳轉到FirstActivity時,系統發現存在有FirstActivity執行個體,但不是位于棧頂,于是重新生成一個執行個體。

這就是singleTop啟動模式,如果發現有對應的Activity執行個體正位于棧頂,則重複利用,不再生成新的執行個體。

3.singleTask

在上面的基礎上我們修改FirstActivity的屬性android:launchMode="singleTask"。示範的結果如下:

Android開發一:Activity之間跳轉的四種launchMode
Android開發一:Activity之間跳轉的四種launchMode
Android開發一:Activity之間跳轉的四種launchMode
Android開發一:Activity之間跳轉的四種launchMode

我們注意到,在上面的過程中,FirstActivity的序列号是不變的,SecondActivity的序列号卻不是唯一的,說明從SecondActivity跳轉到FirstActivity時,沒有生成新的執行個體,但是從FirstActivity跳轉到SecondActivity時生成了新的執行個體。singleTask模式的原理圖如下圖所示:

Android開發一:Activity之間跳轉的四種launchMode

在圖中的下半部分是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 plain copy

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

然後我們再示範一下這個流程:

Android開發一:Activity之間跳轉的四種launchMode
Android開發一:Activity之間跳轉的四種launchMode

我們發現這兩個Activity執行個體分别被放置在不同的棧結構中,關于singleInstance的原理圖如下:

Android開發一:Activity之間跳轉的四種launchMode

我們看到從FirstActivity跳轉到SecondActivity時,重新啟用了一個新的棧結構,來放置SecondActivity執行個體,然後按下後退鍵,再次回到原始棧結構;圖中下半部分顯示的在SecondActivity中再次跳轉到FirstActivity,這個時候系統會在原始棧結構中生成一個FirstActivity執行個體,然後回退兩次,注意,并沒有退出,而是回到了SecondActivity,為什麼呢?是因為從SecondActivity跳轉到FirstActivity的時候,我們的起點變成了SecondActivity執行個體所在的棧結構,這樣一來,我們需要“回歸”到這個棧結構。

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

Android開發一:Activity之間跳轉的四種launchMode

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

[html]  view plain copy

  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 plain copy

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

當我們打開ShareActivity後再按後退鍵回到原來界面時,ShareActivity做為一個獨立的個體存在,如果這時我們打開share應用,無需建立新的ShareActivity執行個體即可看到結果,因為系統會自動查找,存在則直接利用。大家可以在ShareActivity中列印一下taskId,看看效果。關于這個過程,原理圖如下:

Android開發一:Activity之間跳轉的四種launchMode