1. 程式人生 > >(第一行程式碼筆記)活動的4種啟動模式詳解

(第一行程式碼筆記)活動的4種啟動模式詳解

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

為了幫助你可以更好地理解這種啟動模式,我們還是來實踐一下。修改AndroidManifest.xml中SecondActivity的啟動模式:

<activity

    android:name=".SecondActivity"

    android:launchMode="singleInstance">

    <intent-filter>

        <actionandroid:name="com.example.activitytest.ACTION_START" />

        <categoryandroid:name="android.intent.category.DEFAULT" />

        <categoryandroid: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.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中的列印資訊,如圖2所示。



可以看到,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模式的原理示意圖,如圖所示。