1. 程式人生 > >Activity的啟動模式和任務棧(4)

Activity的啟動模式和任務棧(4)

 我們在開發專案的過程中,會涉及到該應用中多個Activity元件之間的跳轉,或者夾帶其它應用的可複用的Activity。例如我們可能希望跳轉到原來某個Activity例項,而不是產生大量重複的 Activity。這樣就需要我們為 Activity 配置特定的載入模式,而不是使用預設的載入模式。

Activity 有四種載入模式

[1] standard 模式

     這是預設模式,每次啟用Activity時都會建立Activity例項,並放入任務棧中。


[2] singleTop 模式

     如果在任務的棧頂正好存在該Activity的例項,就重用該例項( 會呼叫例項的 onNewIntent() ),否則就會建立新的例項並放入棧頂,即使棧中已經存在該Activity的例項,只要不在棧頂,都會建立新的例項。


[3] singleTask 模式

     如果在棧中已經有該Activity的例項,就重用該例項(會呼叫例項的 onNewIntent() )。重用時,會讓該例項回到棧頂,因此在它上面的例項將會被移出棧。如果棧中不存在該例項,將會建立新的例項放入棧中。


[4] singleInstance 模式

     在一個新棧中建立該Activity的例項,並讓多個應用共享該棧中的該Activity例項。一旦該模式的Activity例項已經存在於某個棧中,任何應用再啟用該Activity時都會重用該棧中的例項( 會呼叫例項的 onNewIntent() )。其效果相當於多個應用共享一個應用,不管誰啟用該 Activity 都會進入同一個應用中。


設定啟動模式的位置在 AndroidManifest.xml 檔案中 Activity 元素的 android:launchMode 屬性。

在多Activity開發中,有可能是自己應用之間的Activity跳轉,或者夾帶其他應用的可複用Activity。可能會希望跳轉到原來某個Activity例項,而不是產生大量重複的Activity。

這需要為Activity配置特定的載入模式,而不是使用預設的載入模式。

載入模式分類及在哪裡配置

Activity有四種載入模式:

  • standard
  • singleTop
  • singleTask
  • singleInstance

設定的位置在AndroidManifest.xml檔案中activity元素的android:launchMode屬性:

<activity android:name="ActB" android:launchMode ="singleTask"></activity>

也可以在Eclipse ADT中圖形介面中編輯:

image

區分Activity的載入模式,通過示例一目瞭然。這裡編寫了一個Activity A(ActA)和Activity B(ActB)迴圈跳轉的例子。對載入模式修改和程式碼做稍微改動,就可以說明四種模式的區別。

standard

首先說standard模式,也就是預設模式,不需要配置launchMode。先只寫一個名為ActA的Activity:

例子中都沒有用layout,免得看著羅嗦。可見是ActA –> ActA的例子。在介面中打印出物件的toString值可以根據hash code識別是否建立新ActA例項。

第一個介面:

image

點選按鈕後:

image

可以多點幾次。發現每次都建立了該Activity的新例項。standard的載入模式就是這樣的,intent將傳送給新的例項。

現在點Android裝置的回退鍵,可以看到是按照剛才建立Activity例項的倒序依次出現,類似退棧的操作,而剛才操作跳轉按鈕的過程是壓棧的操作。如下圖:

image

singleTop

singleTop和standard模式,都會將intent傳送新的例項(後兩種模式不傳送到新的例項,如果已經有了的話)。不 過,singleTop要求如果建立intent的時候棧頂已經有要建立的Activity的例項,則將intent傳送給該例項,而不傳送給新的例項。

還是用剛才的示例,只需將launchMode改為singleTop,就能看到區別。

執行的時候會發現,按多少遍按鈕,都是相同的ActiA例項,因為該例項在棧頂,因此不會建立新的例項。如果回退,將退出應用。

image

singleTop模式,可用來解決棧頂多個重複相同的Activity的問題。

如果是A Activity跳轉到B Activity,再跳轉到A Activity,行為就和standard一樣了,會在B Activity跳轉到A Activity的時候建立A Activity的新例項,因為當時的棧頂不是A Activity例項。

ActA類稍作改動:

ActB類:

ActB類使用預設(standard)載入,ActA使用singleTop載入。結果類似下圖:

image

如果把ActA的載入模式改為standard,情況一樣。

現有2個專案,taskA、taskB。taskA負責呼叫taskB中指定的介面。

taskB中有3個介面,a、b、c,每個介面顯示它所在的task id。

SingleTask:

其中b介面被宣告為SingleTask。

先執行taskB,顯示a介面,由a介面呼叫b介面,這時b介面的taskid與a介面的taskid是一致的,說明b介面與a介面在同一個task中;由b介面呼叫c介面時,c介面的taskid與a和b介面的taskid一致,說明這三個介面是在同一個task中。當前顯示的是c介面,此時按Home鍵回到桌面,執行taskA的介面呼叫taskB的b介面,這時b介面顯示出來,它的taskid沒有變,還是之前的taskid,只不過之前顯示的是c介面,這時c介面已經不知所蹤,這時再按back鍵,則回到了a介面,然後是taskA的介面。

這說明,SingleTask所標註的Activity在被自身的app呼叫時,是不新建task的,同時,如果系統中存在了這個SingleTask介面的例項時,會將其所在的task切換到前臺,並把SingleTask介面之後開啟的其他介面全部關閉(有待考證是否關閉)。

另外有一種情況,例如:a介面被呼叫,這時按Home鍵返回到桌面,啟動taskA,並呼叫b介面,這時b介面的taskid與a介面的一致,說明b介面與a介面同屬於一個task。如果直接執行taskA呼叫b介面,b的taskid與taskA的介面的taskid不同,說明在新task中例項化了b介面,由b介面呼叫c介面,c介面的taskid與b介面一致,說明b與c同屬於一個task。

SingleInstance:

將b介面宣告為SingleInstance。

先執行taskB,顯示a介面,由a介面呼叫b介面,這時b介面的taskid與a介面的taskid不同,說明b介面是在新task中生成的例項;由b介面呼叫c介面,c介面的taskid與a介面的taskid相同,說明a、c介面同屬於一個task。

由此可以看出SingleTask與SingleInstance是有本質區別的,而不是像網上說的那樣,都是task的root activity,這是有錯誤的。