Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> activity launchMode

activity launchMode

編輯:關於Android編程

一.Activity的四種啟動模式:

當應用運行起來後就會開啟一條線程,線程中會運行一個任務棧,當Activity實例創建後就會放入任務棧中。

可以根據實際的需求為Activity設置對應的啟動模式,從而可以避免創建大量重復的Activity等問題。

Activity的啟動模式,可以通過AndroidManifest.xml文件中的標簽/元素的屬性Android:launchMode來指定/設置,例如:

;
1.standard(默認啟動模式):

來了intent,每次都創建新的實例。

Standard是默認的模式每開始一個activity,就會在棧中加一個activity,相同的也會加,所以加多少個,就要按多少次返回鍵才能回到最初的界面;

默認啟動模式,每次激活Activity時都會創建Activity,並放入任務棧中,永遠不會調用onNewIntent()。

我們平時直接創建的Activity都是這種模式的Activity,這種模式的Activity的特點是:只要你創建了Activity實例,一旦激活該Activity,則會向任務棧中加入新創建的實例,退出Activity則會在任務棧中銷毀該實例。

對於使用standard模式的活動,系統不會在乎這個活動是否已經在返回棧中存在,每次啟動都會創建該活動的一個新的實例。

例如A啟動A,A再接著啟動A,A繼續啟動A,然後再分別出棧,如圖所示:

\

默認模式,可以不用寫配置。在這個模式下,都會默認創建一個新的實例。因此,在這種模式下,可以有多個相同的實例,也允許多個相同Activity疊加。例如:
若我有一個Activity名為A1,上面有一個按鈕可跳轉到A1。那麼如果我點擊按鈕,便會新啟一個Activity A1疊在剛才的A1之上,再點擊,又會再新啟一個在它之上……
點back鍵會依照棧順序依次退出。


2.singleTop:

來了intent,每次都創建新的實例,僅一個例外:當棧頂的activity恰恰就是該activity的實例(即需要創建的實例)時,不再創建新實例。這解決了棧頂復用問題,想一想,你按兩次back鍵,退出的都是同一個activity,這感覺肯定不爽。

如果任務棧的棧頂已經存在這個activity的實例,不會創建新的activity,而是利用舊的activity實例調用舊的activity的onNewIntent()方法;

作用:避免一個糟糕的用戶體驗,如果這個界面已經被打開且在任務棧的棧頂,就不會重復開啟了;

如果在任務的棧頂正好存在該Activity的實例,就重用該實例,並調用其onNewIntent(),否者就會創建新的實例並放入棧頂(即使棧中已經存在該Activity實例,只要不在棧頂,都會創建實例,而不會調用onNewIntent(),此時就跟standard模式一樣)。

這種模式會考慮當前要激活的Activity實例在任務棧中是否正處於棧頂,如果處於棧頂則無需重新創建新的實例,會重用已存在的實例,否則會在任務棧中創建新的實例。

\

可以有多個實例,但是不允許多個相同Activity疊加。即,如果Activity在棧頂的時候,啟動相同的Activity,不會創建新的實例,而會調用其onNewIntent方法。例如:
若我有兩個Activity名為B1,B2,兩個Activity內容功能完全相同,都有兩個按鈕可以跳到B1或者B2,唯一不同的是B1為standard,B2為singleTop。
若我意圖打開的順序為B1->B2->B2,則實際打開的順序為B1->B2(後一次意圖打開B2,實際只調用了前一個的onNewIntent方法)
若我意圖打開的順序為B1->B2->B1->B2,則實際打開的順序與意圖的一致,為B1->B2->B1->B2。
3.singleTask:

來了intent後,檢查棧中是否存在該activity的實例,如果存在就把intent發送給它;

如果要激活的那個Activity在任務棧中存在該實例,則不需要創建,只需要把此Activity放入棧頂,並把該Activity以上的Activity實例都pop移除;

在任務棧裡面只允許一個實例存在,假如02是singletask,棧裡是:01 02 01 03 若此時開啟02,則會復用這個已經存在的activity,並且把當前activity上面其他的activity從任務棧裡清空!

相當於條用onNewIntent()+ClearTop;

1.設置了"singleTask"啟動模式的Activity,它在啟動的時候,會先在系統中查找屬性值affinity等於它的屬性值taskAffinity的任務存在;如果存在這樣的任務,它就會在這個任務中啟動,否則就會在新任務中啟動。因此,如果我們想要設置了"singleTask"啟動模式的Activity在新的任務中啟動,就要為它設置一個獨立的taskAffinity屬性值。

2.如果設置了"singleTask"啟動模式的Activity不是在新的任務中啟動時,它會在已有的任務中查看是否已經存在相應的Activity實例,如果存在,就會把位於這個Activity實例上面的Activity全部結束掉,即最終這個Activity實例會位於任務的堆棧頂端中。

應用場景:浏覽器:底層使用的是webkit c內核,初始化一次需要申請很多的內存資源,占用cpu時間,所以使用singletask,保證在任務棧裡只會有一個實例存在;

否則就創建一個新的該activity的實例,放入一個新的task棧的棧底。肯定位於一個task的棧底,而且棧中只能有它一個該activity實例,但允許其他activity加入該棧。解決了在一 個task中共享一個activity。

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

如果任務棧中存在該模式的Activity實例,則把棧中該實例以上的Activity實例全部移除,調用該實例的newInstance()方法重用該Activity,使該實例處於棧頂位置,否則就重新創建一個新的Activity實例。

大家遇到一個應用的Activity供多種方式調用啟動的情況,多個調用希望只有一個Activity的實例存在,這就需要Activity的onNewIntent(Intent intent)方法了。只要在Activity中加入自己的onNewIntent(intent)的實現加上Manifest中對Activity設置lanuchMode=“singleTask”就可以。

onNewIntent()非常好用,Activity第一啟動的時候執行onCreate()---->onStart()---->onResume()等後續生命周期函數,也就時說第一次啟動Activity並不會執行到onNewIntent().而後面如果再有想啟動Activity的時候,那就是執行onNewIntent()---->onResart()------>onStart()----->onResume().如果android系統由於內存不足把已存在Activity釋放掉了,那麼再次調用的時候會重新啟動Activity即執行onCreate()---->onStart()---->onResume()等。

當調用到onNewIntent(intent)的時候,需要在onNewIntent()中使用setIntent(intent)賦值給Activity的Intent.否則,後續的getIntent()都是得到老的Intent。

當活動的啟動模式指定為singleTask,每次啟動該活動時系統首先會在返回棧中檢查是否存在該活動的實例,如果發現已經存在則直接使用該實例,並把在這個活動之上的所有活動統統出棧,如果沒有發現就會創建一個新的活動實例。

 

\

 

只有一個實例。在同一個應用程序中啟動他的時候,若Activity不存在,則會在當前task創建一個新的實例,若存在,則會把task中在其之上的其它Activity destory掉並調用它的onNewIntent方法。

如果是在別的應用程序中啟動它,則會新建一個task,並在該task中啟動這個Activity,singleTask允許別的Activity與其在一個task中共存,也就是說,如果我在這個singleTask的實例中再打開新的Activity,這個新的Activity還是會在singleTask的實例的task中。例如:

若我的應用程序中有三個Activity,C1,C2,C3,三個Activity可互相啟動,其中C2為singleTask模式,那麼,無論我在這個程序中如何點擊啟動,如:C1->C2->C3->C2->C3->C1-C2,C1,C3可能存在多個實例,但是C2只會存在一個,並且這三個Activity都在同一個task裡面。

但是C1->C2->C3->C2->C3->C1-C2,這樣的操作過程實際應該是如下這樣的,因為singleTask會把task中在其之上的其它Activity destory掉。

操作:

1.C1->C2;

2.C1->C2->C3;

3.C1->C2->C3->C2;

4.C1->C2->C3->C2->C3->C1;

5.C1->C2->C3->C2->C3->C1-C2;

實際:

1.C1->C2;

2.C1->C2->C3;

3.C1->C2;

4.C1->C2->C3->C1;

5.C1->C2;

若是別的應用程序打開C2,則會新啟一個task。

如別的應用Other中有一個activity,taskId為200,從它打開C2,則C2的taskIdI不會為200,例如C2的taskId為201,那麼再從C2打開C1、C3,則C2、C3的taskId仍為201。

注意:如果此時你點擊home,然後再打開Other,發現這時顯示的肯定會是Other應用中的內容,而不會是我們應用中的C1 C2 C3中的其中一個。

4.singleInstance:

肯定位於一個task的棧底,並且是該棧唯一的activity。解決了多個task共享一個activity。

singleInstance的啟動模式更加極端,開啟新的activity,會給自己創建一個單獨的任務棧,不管是從應用內部打開還是通過其他應用調用TaskId是單獨的,已存在的則只需調用onNewIntent();

應用場景:

在整個手機操作系統裡面只會有一個該activity的實例存在,所以多個應用程序共享這個activity的實例,有線程安全問題!

例如鬧鈴提醒,將鬧鈴提醒與鬧鈴設置分離;

在一個新棧中創建該Activity實例,並讓多個應用共享改棧中的該Activity實例。一旦改模式的Activity的實例存在於某個棧中,任何應用再激活改Activity時都會重用該棧中的實例,其效果相當於多個應用程序共享一個應用,不管誰激活該Activity都會進入同一個應用中。

當該模式Activity實例在任務棧中創建後,只要該實例還在任務棧中,即只要激活的是該類型的Activity,都會通過調用實例的newInstance()方法重用該Activity,此時使用的都是同一個Activity實例,它都會處於任務棧的棧頂。此模式一般用於加載較慢的,比較耗性能且不需要每次都重新創建的Activity

使用singleInstance模式就可以解決這個問題,在這種模式下會有一個單獨的返回棧來管理這個活動,不管是哪個應用程序來訪問這個活動,都共用的同一個返回棧,也就解決了共享活動實例的問題。

假設B啟動A,A啟動C,其中A的啟動模式為singleInstance,則:

 

\

 

返回的頁面順序是C-B-A;

只有一個實例,並且這個實例獨立運行在一個task中,這個task只有這個實例,不允許有別的Activity存在。例如:

程序有三個ActivityD1,D2,D3,三個Activity可互相啟動,其中D2為singleInstance模式。那麼程序從D1開始運行,假設D1的taskId為200,那麼從D1啟動D2時,D2會新啟動一個task,即D2與D1不在一個task中運行。假設D2的taskId為201,再從D2啟動D3時,D3的taskId為200,也就是說它被壓到了D1啟動的任務棧中。

若是在別的應用程序打開D2,假設Other的taskId為200,打開D2,D2會新建一個task運行,假設它的taskId為201,那麼如果這時再從D2啟動D1或者D3,則又會再創建一個task,因此,若操作步驟為other->D2->D1,這過程就涉及到了3個task了。

二.小結:

這4中模式又分兩類,standard和signleTop屬於一類,singleTask和signleInstance屬於另一類。

standard和singleTop屬性的Activity的實例可以屬於任何任務(Task),並且可以位於Activity堆棧的任何位置。比較典型的一種情況是,一個任務的代碼執行startActivity(),如果傳遞的Intent對象沒有包含FLAG_ACTIVITY_NEW_TASK屬性,指定的Activity將被該任務調用,從而裝入該任務的Activity堆棧中。standard和singleTop的區別在於:standard模式的Activity在被調用時會創建一個新的實例,所有實例處理同一個Intent對象;但對於singleTop模式的Activity,如果被調用的任務已經有一個這樣的Activity在堆棧的頂端,那麼不會有新的實例創建,任務會使用當前頂端的Activity實例來處理Intent對象,換句話說,如果被調用的任務包含一個不在堆棧頂端的singleTop Activity,或者堆棧頂端為singleTop的Activity的任務不是當前被調用的任務,那麼,仍然會有一個新的Activity對象被創建。

singleTask和singleInstance模式的Activity僅可用於啟動任務的情況,這種模式的Activity總是處在Activity堆棧的最底端,並且一個任務中只能被實例化一次。兩者的區別在於:對於singleInstance模式的Activity,任務的Activity堆棧中如果有這樣的Activity,那它將是堆棧中的唯一的Activity,當前任務收到的Intent都由它處理,由它開啟的其他Activity將在其他任務中被啟動;對於SingleTask模式的Activity,它在堆棧底端,其上方可以有其他Activity被創建,但是,如果發給該Activity的Intent對象到來時該Activity不在堆棧頂端,那麼該Intent對象將被丟棄,但是界面還是會切換到當前的Activity。

在多Activity開發中,有可能是自己應用間的activity跳轉,或者夾帶其他應用的可復用activity。可能會希望跳轉到原來某個activity實例,而非產生多個重復的activity。我們可借助activity四種啟動模式來實現不同的需求:

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