activity的啟動模式

blueizz發表於2017-04-09

一、Activity四種啟動模式
啟動Activity時,系統會建立Activity例項並將它放入任務棧中。任務棧是一種“先進後出”的棧結構,當棧中無任何Activity時,系統就會回收這個任務棧。
(1)standard:系統的預設模式。每次啟動一個Activity都會重新建立一個新的例項,不管這個例項是否已經存在。當我們用ApplicationContext去啟動standard模式的Activity會報錯,這是由於非Activity型別的Context並沒有所謂的任務棧。解決這個問題的方法是為待啟動的Activity指定FLAG_ACTIVITY_NEW_TASK標記位,這樣啟動時就會為它建立一個新的任務棧,此時待啟動Activity實際上是以singleTask模式啟動的。
(2)singleTop:棧頂複用模式。在這種模式下,如果新Activity已經位於任務棧的棧頂,那麼此Activity不會被重新建立,同時它的onNewIntent方法會被回撥,onCreate、onStart不會被呼叫。如果新Activity的例項已存在但不是位於棧頂,那麼它仍然會被重新建立。

/**
  * @param intent  
  * 通過intent可以取出當前請求的資訊
 */
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
}

(3)singleTask:棧內複用模式。這是一種單例項模式,在這種模式下,只要Activity在一個棧中存在,那麼多次啟動此Activity都不會重新建立例項,和singleTop一樣,系統也會回撥其onNewIntent方法。具體一點,當一個具有singleTask模式的Activity請求啟動後,比如Activity A,系統首先會尋找是否存在A想要的任務棧,如果不存在,就重新建立一個任務棧,然後建立A的例項後把A放入棧中。如果存在A所需要的任務棧,這時要看A是否在棧中有例項存在,如果例項不存在,就建立A的例項並把A壓入棧中;如果有例項存在,那麼系統就會把A調到棧頂並呼叫它的onNewIntent方法,同時由於singleTask預設具有clearTop的效果,會導致棧內所有在A上面的Activity全部出棧。
(4)singleInstance:單例項模式。這是一種加強的singleTask模式,它除了具有singleTask模式的所有特性外,還加強了一點,那就是具有此種模式的Activity只能單獨地位於一個任務棧中。

總結
在沒有設定taskAffinity的前提下,除了singleInstance模式外,誰啟動了這個Activity,那麼這個Activity就執行在啟動它的那個Activity所在的棧中。


二、指定啟動模式
(1)通過AndroidMenifest為Activity指定啟動模式

<activity
    android:name=".SecondActivity"
    android:configChanges="orientation"
    android:launchMode="singleTop" />

(2)通過在Intent中設定標誌位來為Activity指定啟動模式

Intent intent = new Intent(MainActivity.this,SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

優先順序上,第二種方式的優先順序要高於第一種,當兩種同時存在時,以第二種方式為準;第一種方式無法直接為Activity設定FLAG_ACTIVITY_CLEAR_TOP標識,而第二種方式無法為Activity指定singleInstance模式。


三、Activity的Flags
Activity的標誌位有很多,有的標誌位可以設定Activity的啟動模式,有的標誌位可以影響Activity的執行狀態,下面主要介紹幾種比較常用的標誌位:

(1)FLAG_ACTIVITY_NEW_TASK
這個標誌位的作用是為Activity指定“singleTask”啟動模式,其效果和在XML中指定該啟動模式相同。

(2)FLAG_ACTIVITY_SINGLE_TOP
這個標誌位的作用是為Activity指定“singleTop”啟動模式,其效果和在XML中指定該啟動模式相同。

(3)FLAG_ACTIVITY_CLEAR_TOP
具有此標誌位的Activity,當它啟動時,在同一個任務棧中所有位於它上面的Activity都要出棧。這個標誌位一般會和singleTask啟動模式一起出現,在這種情況下,被啟動Activity的例項如果已經存在,那麼系統就會呼叫它的onNewIntent。如果被啟動的Activity採用standard模式啟動,那麼它連同它之上的Activity都要出棧,系統會建立新的Activity例項並放入棧頂。singleTask啟動模式預設就具有此標誌位的效果。

(4)FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
具有這個標誌位的Activity不會出現在歷史Activity的列表中,當某些情況下我們不希望使用者通過歷史列表回到我們的Activity的時候這個標誌位比較有用。它等同於在XML中指定Activity的屬性android:excludeFromRecents=”true”。


四、任務棧
任務棧分為前臺任務棧和後臺任務棧。當使用者開啟了一個新的任務棧,或者點選Home鍵回到主螢幕的時候,之前任務就會被轉移到後臺。當任務處於後臺狀態的時候,任務棧中所有的Activity都會進入暫停狀態,但這些Activity在棧中的順序都會原封不動地保留著。預設情況下,所有Activity啟動後,所在的任務棧的名字都為應用的包名,但是如果在AndroidMenifest中為Activity指定了taskAffinity屬性,此時Activity啟動後所在的任務棧名字就是指定的taskAffinity屬性的值。
taskAffinity屬性主要和singleTask啟動模式或者allowTaskReparenting屬性配對使用,在其他情況下沒有意義。當taskAffinity和singleTask啟動模式配對使用的時候,它是具有該模式的Activity的目前任務棧的名字,待啟動的Activity會執行在名字和taskAffinity相同的任務棧中。

相關文章