Android的四種啓動模式

Android的四種啓動模式一共有四種,分別是standard,singleTop,singleTask,singleInstance,可以在AndroidMainfest.xml中通過給標籤指定android:lanuchMode屬性來選擇啓動模式。

1.standard:
standard 是活動默認的啓動模式,在不進行顯式指定的情況下,所有活動都會自動使用這種啓動模式。你已經知道了 Android 是使用返回棧來管理活動的,在 standard 模式(即默認情況)下,每當啓動一個新的活動,它就會在返回棧中入棧,並處於棧頂的位置。對於使用standard 模式的活動,系統不會在乎這個活動是否已經在返回棧中存在,每次啓動都會創建該活動的一個新的實例。下面新建一個項目來了解一下:

修改 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 中打印信息。

這裏寫圖片描述

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

2.singleTop:

當活動的啓動模式指定爲 singleTop, 在啓動活動時如果發現返回棧的棧頂已經是該活動, 則認爲可以直接使用它,不會再創建新的活動實例。
修改 AndroidManifest.xml 中 FirstActivity 的啓動模式,如下所示:

<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" />
</intent-filter>
</activity>

然後重新運行程序, 查看 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 中的打印信息

這裏寫圖片描述

可以看到系統創建了兩個不同的 FirstActivity 實例,這是由於在 SecondActivity 中再次啓動 FirstActivity 時, 棧頂活動已經變成了 SecondActivity, 因此會創建一個新的 FirstActivity實例。現在按下 Back 鍵會返回到 SecondActivity,再次按下 Back 鍵又會回到 FirstActivity,再按一次 Back 鍵纔會退出程序。

3.singleTask:

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

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

<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" />
</intent-filter>
</activity>

然後在 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 鍵就可以退出程序。

4.singleInstance

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

還是來實踐一下。 修改 AndroidManifest.xml 中 SecondActivity 的啓動模式:

<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" />
</intent-filter>
</activity>

我們先將 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.activity_first);

        Button btn1 = (Button) findViewById(R.id.btn1);

        btn1.setOnClickListener(new View.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.activity_second);

        Button btn2 = (Button) findViewById(R.id.btn2);

        btn2.setOnClickListener(new View.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.activity_third);
    }

仍然是在 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 鍵, 這時所有返回棧都已經空了,也就自然退出了程序。

相信大家通過實踐和分析對於這四種啓動模式已經初步的瞭解,具體實踐可以帶到以後的項目中去體會。

發佈了13 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章