Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 詳解Android開發中Activity的四種launchMode

詳解Android開發中Activity的四種launchMode

編輯:關於Android編程

Activity棧主要用於管理Activity的切換。當使用Intent跳轉至某個目標Activity,需要根據目標Activity的加載模式來加載。

Activity一共有以下四種launchMode:

1.standard:默認,每次使用Intent跳轉到目標Activity時都創建一個新的實例。壞處是每次進入都要創建新的實例,執行OnCreate方法。

201638150942001.jpg (1240×930)

2.singleTop:如果要跳轉的目標Activity正好在task的頂部(說明當前肯定不在目標task裡,例如我在微信首頁,然後想使用Intent跳轉到InnoXYZ應用的首頁,那麼加入InnoXYZ首頁正好在InnoXYZ的task頂部,就直接跳轉而不會創建實例),那麼就直接跳轉過去而不會創建新的。(例子,當前在Home Screen, 收到一條微信首頁的推送,而此時task棧裡的微信task裡的Activity棧裡的最頂部正好就是微信首頁,那麼點擊推送就直接進入該實例而不會創建新的實例)

201638151101876.jpg (1240×930)

3.singleTask:會在一個新的task中產生這個實例,以後每次調用都會使用這個,不會去產生新的實例了。

4.singleInstance:是其所在棧的唯一activity,它會每次都被重用。

launchMode在多個Activity跳轉的過程中扮演著重要的角色,它可以決定是否生成新的Activity實例,是否重用已存在的Activity實例,是否和其他Activity實例公用一個task裡。這裡簡單介紹一下task的概念,task是一個具有棧結構的對象,一個task可以管理多個Activity,啟動一個應用,也就創建一個與之對應的task。

我們可以在AndroidManifest.xml配置<activity>的android:launchMode屬性為以上四種之一即可。
下面我們結合實例一一介紹這四種lanchMode:
1.standard
standard模式是默認的啟動模式,不用為<activity>配置android:launchMode屬性即可,當然也可以指定值為standard。
我們將會一個Activity,命名為FirstActivity,來演示一下標准的啟動模式。FirstActivity代碼如下:

standard模式是默認的啟動模式,不用為<activity>配置android:launchMode屬性即可,當然也可以指定值為standard。
我們將會一個Activity,命名為FirstActivity,來演示一下標准的啟動模式。FirstActivity代碼如下:

package com.scott.launchmode; 
 
import android.app.Activity; 
import android.content.Intent; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.Button; 
import android.widget.TextView; 
 
public class FirstActivity extends Activity { 
  @Override 
  public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.first); 
    TextView textView = (TextView) findViewById(R.id.textView); 
    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(FirstActivity.this, FirstActivity.class); 
        startActivity(intent); 
      } 
    }); 
  } 
} 

我們FirstActivity界面中的TextView用於顯示當前Activity實例的序列號,Button用於跳轉到下一個FirstActivity界面。
然後我們連續點擊幾次按鈕,將會出現下面的現象:

201638151308968.gif (320×120)201638151209028.gif (320×121)201638151327302.gif (319×127)

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

201638151352070.gif (440×212)

如圖所示,每次跳轉系統都會在task中生成一個新的FirstActivity實例,並且放於棧結構的頂部,當我們按下後退鍵時,才能看到原來的FirstActivity實例。
這就是standard啟動模式,不管有沒有已存在的實例,都生成新的實例。

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

201638151417517.gif (320×124)201638151838515.gif (320×124)201638151858469.gif (320×124)

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

201638151434213.gif (522×176)

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

package com.scott.launchmode; 
 
import android.app.Activity; 
import android.content.Intent; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.Button; 
import android.widget.TextView; 
 
public class SecondActivity extends Activity { 
  @Override 
  protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.second); 
    TextView textView = (TextView) findViewById(R.id.textView); 
    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.class); 
startActivity(intent); 

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

201638151515857.gif (319×123)201638151530469.gif (320×118)201638151550299.gif (320×116)

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

201638151628506.gif (320×119)201638151647962.gif (320×120)201638151701357.gif (320×119)201638151723858.gif (320×120)

我們看到,當從SecondActivity跳轉到FirstActivity時,系統發現存在有FirstActivity實例,但不是位於棧頂,於是重新生成一個實例。
這就是singleTop啟動模式,如果發現有對應的Activity實例正位於棧頂,則重復利用,不再生成新的實例。

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

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

201638151803687.gif (440×400)

在圖中的下半部分是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添加如下代碼:

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

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

201638151951749.gif (320×142)201638152011045.gif (319×139)

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

201638152030493.gif (692×373)

我們看到從FirstActivity跳轉到SecondActivity時,重新啟用了一個新的棧結構,來放置SecondActivity實例,然後按下後退鍵,再次回到原始棧結構;圖中下半部分顯示的在SecondActivity中再次跳轉到FirstActivity,這個時候系統會在原始棧結構中生成一個FirstActivity實例,然後回退兩次,注意,並沒有退出,而是回到了SecondActivity,為什麼呢?是因為從SecondActivity跳轉到FirstActivity的時候,我們的起點變成了SecondActivity實例所在的棧結構,這樣一來,我們需要“回歸”到這個棧結構。
如果我們修改FirstActivity的launchMode值為singleTop、singleTask、singleInstance中的任意一個,流程將會如圖所示:

201638152048827.gif (636×174)

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:

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

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

201638152118151.gif (576×155)

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved