Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android]活動的啟動模式

[Android]活動的啟動模式

編輯:關於Android編程

啟動模式一共有四種,分別是 standard、singleTop、singleTask 和 singleInstance , 可 以 在 AndroidManifest.xml 中 通 過 給 標 簽 指 定android:launchMode 屬性來選擇啟動模式。在實際項目中我們應該根據特定的需求為每個活動指定恰當的啟動模式。

1. standard

standard 是活動默認的啟動模式,在不進行顯式指定的情況下,所有活動都會自動使用這種啟動模式。因此,到目前為止我們寫過的所有活動都是使用的 standard 模式。經過之前的學習,我們已經知道了 Android 是使用活動棧來管理活動的,在 standard 模式(即默認情況)下,每當啟動一個新的活動,它就會在活動棧中入棧,並處於棧頂的位置。對於使用standard 模式的活動,系統不會在乎這個活動是否已經在活動棧中存在,每次啟動都會創建該活動的一個新的實例。我們現在通過實踐來體會一下 standard 模式,這次還是准備在 ActivityTest 項目的基礎上修改,打開 ActivityTest 項目。

修改 FirstActivity 中 onCreate()方法的代碼,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d("FirstActivity", this.toString());
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.first_layout);
    Button button1 = (Button) findViewById(R.id.button_1);

    button1.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
            startActivity(intent);
        }
    });
}

代碼看起來有些奇怪吧,在 FirstActivity 的基礎上啟動 FirstActivity。從邏輯上來講這確實沒什麼意義,不過我們的重點在於研究 standard 模式,因此不必在意這段代碼有什麼實際用途。另外我們還在 onCreate()方法中添加了一行打印信息,用於打印當前活動的實例。

現在重新運行程序,然後在 FirstActivity 界面連續點擊兩次按鈕,可以看到 LogCat 中打印信息如圖所示。
LogCat信息

從打印信息中我們就可以看出, 每點擊一次按鈕就會創建出一個新的 FirstActivity 實例。此時返回棧中也會存在三個 FirstActivity的實例, 因此你需要連按三次 Back鍵才能退出程序。

standard 模式的原理示意圖,如下圖所示:
這裡寫圖片描述

2. SingleTop

可能在有些情況下,你會覺得 standard 模式不太合理。活動明明已經在棧頂了,為什麼再次啟動的時候還要創建一個新的活動實例呢?別著急,這只是系統默認的一種啟動模式而已,你完全可以根據自己的需要進行修改,比如說使用 singleTop 模式。當活動的啟動模式指定為 singleTop,在啟動活動時如果發現活動棧的棧頂已經是該活動,則認為可以直接使用它,不會再創建新的活動實例。我們通過實踐來體會一下,修改 AndroidManifest.xml 中 FirstActivity 的啟動模式,如下所示:

<code class="language-xml hljs "><activity android:name=".FirstActivity" android:launchmode="singleTop" android:label="This is FirstActivity">

    <intent-filter>
        <action android:name="android.intent.action.MAIN">
        <category android:name="android.intent.category.LAUNCHER">
    </category></action></intent-filter>
</activity></code>

然後重新運行程序,查看 LogCat 會看到已經創建了一個 FirstActivity 的實例,如下圖所示:
這裡寫圖片描述

但是之後不管你點擊多少次按鈕都不會再有新的打印信息出現,因為目前 FirstActivity已經處於返回棧的棧頂,每當想要再啟動一個 FirstActivity 時都會直接使用棧頂的活動,因此 FirstActivity 也只會有一個實例,僅按一次 Back 鍵就可以退出程序。不過當 FirstActivity 並未處於棧頂位置時,這時再啟動 FirstActivity,還是會創建新的實例的。下面我們來實驗一下,修改 FirstActivity 中 onCreate()方法的代碼,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d("FirstActivity", this.toString());
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.first_layout);
    Button button1 = (Button) findViewById(R.id.button_1);

    button1.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(FirstActivity.this,
            SecondActivity.class);
            startActivity(intent);
        }
    });
}

這次我們點擊按鈕後啟動的是 SecondActivity。然後修改SecondActivity 中 onCreate()方法的代碼,如下所示:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d("SecondActivity", this.toString());
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.second_layout);
    Button button2 = (Button) findViewById(R.id.button_2);

    button2.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(SecondActivity.this,
            FirstActivity.class);
            startActivity(intent);
        }
    });
}

我們在 SecondActivity 中的按鈕點擊事件裡又加入了啟動 FirstActivity 的代碼。現在重新運行程序,在 FirstActivity 界面點擊按鈕進入到 SecondActivity,然後在 SecondActivity 界面點擊按鈕,又會重新進入到 FirstActivity。
查看 LogCat 中的打印信息,如下圖所示:
這裡寫圖片描述vc+1zbO0tL2owcvBvbj2srvNrLXEIEZpcnN0QWN0aXZpdHkgyrXA/aOs1eLKx9PJ09rU2iBTZWNvbmRBY3Rpdml0eSDW0NTZtM7G9LavIEZpcnN0QWN0aXZpdHkgyrGjrCDVu7alu+62r9LRvq2x5LPJwcsgU2Vjb25kQWN0aXZpdHmjrCDS8rTLu+G0tL2o0ru49tDCtcQgRmlyc3RBY3Rpdml0ecq1wP2ho8/W1NqwtM/CIEJhY2sgvPy74be1u9i1vSBTZWNvbmRBY3Rpdml0eaOs1Nm0zrC0z8IgQmFjayC8/NPWu+G72LW9IEZpcnN0QWN0aXZpdHmjrNTZsLTSu7TOIEJhY2sgvPyyxbvhzcuz9rPM0PKho3NpbmdsZVRvcCDEo8q9tcTUrcDtyr7S4s28o6zI58/CzbzL+cq+o7o8YnIgLz4NCjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20160405/20160405093758326.jpg" title="\" />

3. SingleTask

使用 singleTop 模式可以很好地解決重復創建棧頂活動的問題,但是正如你在前文所看到的,如果該活動並沒有處於棧頂的位置,還是可能會創建多個活動實例的。那麼有沒有什麼辦法可以讓某個活動在整個應用程序的上下文中只存在一個實例呢?這就要借助singleTask 模式來實現了。當活動的啟動模式指定為 singleTask,每次啟動該活動時系統首先會在活動棧中檢查是否存在該活動的實例,如果發現已經存在則直接使用該實例,並把在這個活動之上的所有活動統統出棧,如果沒有發現就會創建一個新的活動實例。

我們還是通過代碼來更加直觀地理解一下。修改 AndroidManifest.xml 中 FirstActivity 的啟動模式:

<code class="language-xml hljs "><activity android:name=".FirstActivity" android:launchmode="singleTask" android:label="This is FirstActivity">

    <intent-filter>
        <action android:name="android.intent.action.MAIN">
        <category android:name="android.intent.category.LAUNCHER">
    </category></action></intent-filter>
</activity></code>

然後在 FirstActivity 中添加 onRestart()方法,並打印日志:

@Override
protected void onRestart() {
    super.onRestart();
    Log.d("FirstActivity", "onRestart");
}

最後在 SecondActivity 中添加 onDestroy()方法,並打印日志:

@Override
protected void onDestroy() {
    super.onDestroy();
    Log.d("SecondActivity", "onDestroy");
}

現在重新運行程序,在 FirstActivity 界面點擊按鈕進入到 SecondActivity,然後在SecondActivity 界面點擊按鈕,又會重新進入到 FirstActivity。

查看 LogCat 中的打印信息,如下圖所示:
這裡寫圖片描述

其實從打印信息中就可以明顯看出了,在 SecondActivity 中啟動 FirstActivity 時,會發現活動棧中已經存在一個 FirstActivity 的實例,並且是在 SecondActivity 的下面,於是SecondActivity 會從活動棧中出棧,而 FirstActivity 重新成為了棧頂活動,因此 FirstActivity的 onRestart()方法和 SecondActivity 的 onDestroy()方法會得到執行。現在活動棧中應該只剩下一個 FirstActivity 的實例了,按一下 Back 鍵就可以退出程序。

singleTask 模式的原理示意圖,如下圖所示:
這裡寫圖片描述

4. SingleInstance

singleInstance 模式應該算是四種啟動模式中最特殊也最復雜的一個了,你也需要多花點功夫來理解這個模式。不同於以上三種啟動模式,指定為 singleInstance 模式的活動會啟用一個新的活動棧來管理這個活動(其實如果 singleTask 模式指定了不同的 taskAffinity,也會啟動一個新的活動棧) 。那麼這樣做有什麼意義呢?想象以下場景,假設我們的程序中有一個活動是允許其他程序調用的,如果我們想實現其他程序和我們的程序可以共享這個活動的實例,應該如何實現呢?使用前面三種啟動模式肯定是做不到的,因為每個應用程序都會有自己的活動棧,同一個活動在不同的活動棧中入棧時必然是創建了新的實例。而使用singleInstance 模式就可以解決這個問題,在這種模式下會有一個單獨的活動棧來管理這個活動,不管是哪個應用程序來訪問這個活動,都共用的同一個活動棧,也就解決了共享活動實例的問題。

xml 中 SecondActivity 的啟動模式:

<code class=" hljs xml"><activity android:name=".SecondActivity" android:launchmode="singleInstance">

    <intent-filter>
        <action android:name="com.example.activitytest.ACTION_START">
        <category android:name="android.intent.category.DEFAULT">
        <category android:name="com.example.activitytest.MY_CATEGORY">
    </category></category></action></intent-filter>
</activity></code>

我們先將 SecondActivity 的啟動模式指定為 singleInstance,然後修改 FirstActivity 中onCreate()方法的代碼:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d("FirstActivity", "Task id is " + getTaskId());
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.first_layout);
    Button button1 = (Button) findViewById(R.id.button_1);

    button1.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(FirstActivity.this,
            SecondActivity.class);
            startActivity(intent);
        }
    });
} 

在onCreate()方法中打印了當前返回棧的 id。然後修改 SecondActivity 中 onCreate()方法的代碼:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d("SecondActivity", "Task id is " + getTaskId());
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.second_layout);
    Button button2 = (Button) findViewById(R.id.button_2);

    button2.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(SecondActivity.this,
            ThirdActivity.class);
            startActivity(intent);
        }
    });
}

同樣在 onCreate()方法中打印了當前返回棧的 id,然後又修改了按鈕點擊事件的代碼,用於啟動 ThirdActivity。最後修改 ThirdActivity 中 onCreate()方法的代碼:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d("ThirdActivity", "Task id is " + getTaskId());
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.third_layout);
}

仍然是在 onCreate()方法中打印了當前返回棧的 id。現在重新運行程序,在 FirstActivity界 面 點 擊 按 鈕 進 入 到 SecondActivity , 然 後 在 SecondActivity 界 面 點 擊 按 鈕 進 入 到ThirdActivity。
查看 LogCat 中的打印信息,如下圖所示:
這裡寫圖片描述

可以看到, SecondActivity 的 Task id 不同於 FirstActivity 和 ThirdActivity,這說明SecondActivity 確實是存放在一個單獨的活動棧裡的, 而且這個棧中只有 SecondActivity 這一個活動。然後我們按下 Back 鍵進行返回, 你會發現 ThirdActivity 竟然直接返回到了 FirstActivity,再按下 Back 鍵又會返回到 SecondActivity,再按下 Back 鍵才會退出程序,這是為什麼呢?其實原理很簡單,由於 FirstActivity 和 ThirdActivity 是存放在同一個活動棧裡的,當在
ThirdActivity 的界面按下 Back 鍵,ThirdActivity 會從活動棧中出棧,那麼 FirstActivity 就成為了棧頂活動顯示在界面上,因此也就出現了從 ThirdActivity 直接返回到 FirstActivity 的情況。然後在 FirstActivity 界面再次按下 Back 鍵,這時當前的活動棧已經空了,於是就顯示了另一個活動棧的棧頂活動,即 SecondActivity。最後再次按下 Back 鍵,這時所有活動棧都已空了,也就自然退出了程序。

singleInstance 模式的原理示意圖,如下圖所示:
這裡寫圖片描述

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