Android任務和返回棧簡單總結

tuacy發表於2017-11-02

       任務是指在執行特定作業時與使用者互動的一系列 Activity。 這些 Activity 按照各自的開啟順序排列在堆疊(即返回棧)中。一般情況下我們可以認為一個應用就是一個任務,並且這個應用啟動的所有Activity會按照開啟的順序放入堆疊中即是這個任務對應的返回棧。

       手機的主螢幕是大多數任務的起點。當使用者觸控應用啟動器中的圖示(或主螢幕上的快捷方式)時,該應用的任務將出現在前臺。 如果應用不存在任務(應用最近未曾使用),則會建立一個新任務,並且該應用的“主”Activity 將作為堆疊中的根 Activity 開啟。

       一般我們把任務分為兩種:前臺任務和後臺任務。當使用者開始新任務或通過“主頁”按鈕轉到主螢幕時,當前任務被移動到“後臺”。 儘管該任務在“後臺”,任務中的所有 Activity 全部停止,但是任務的返回棧仍舊不變,也就是說,當任務被切換到“後臺”時,該任務僅僅失去焦點而已。在必要的時候我們還是可以把這個任務切換到“前臺”來。要注意的一個點就是,如果後臺執行的任務太多的時候,系統可能會銷燬後臺 Activity,以回收記憶體資源,從而導致 Activity 狀態丟失

任務返回棧的入棧:啟動新的Activity。
任務返回棧的出棧:銷燬棧頂的Activity(如BACK按鍵操作)。

一 任務的預設行為

       預設情況下,一個應用對應一個任務對應一個返回棧。如果應用之前沒有被啟動過,點選主螢幕應用啟動器中的圖示的時候會生成一個全新的任務,並且該應用的“主”Activity 將作為任務返回棧中的根 Activity 開啟,之後依次開啟的Activity會按照開啟的順序壓入返回棧中。當按”BACK”鍵返回時,這些壓入返回棧中的Activity會按照“後進先出”的原則依次出棧,恢復回退棧中前一個 Activity 的執行。

這裡寫圖片描述

       預設情況下,使用者通過按“HOME”按鈕離開任務時,當前 Activity 將停止且當前Activity對應的任務會進入後臺。 系統將保留任務中每個 Activity 的狀態。如果使用者稍後通過選擇開始任務的啟動器圖示來恢復任務,則任務將出現在前臺並恢復執行堆疊頂部的 Activity。

這裡寫圖片描述

       預設情況下的行為總結如下:

  • Activity 可以被多次例項化不管Activity是不是有相同的taskAffinity(不管是來自當前任務的Activity還是其他任務的Activity)。
  • 如果使用者按“返回”按鈕,則當前 Activity 會從堆疊彈出並被銷燬。 堆疊中的前一個 Activity 恢復執行。
  • 同一個入口的所有Activity都會放入同一個返回棧中。

二 任務的管理

       如上所述預設行為(將所有連續啟動的 Activity 放入同一任務和“後進先出”堆疊中)非常適用於大多數應用,而您不必擔心 Activity 如何與任務關聯或者如何存在於返回棧中。 但是,有的時候您可能會決定要中斷正常行為, 也許您希望應用中的 Activity 在啟動時開始新任務(而不是放置在當前任務中);或者,當啟動 Activity 時,您希望將其現有例項上移一層(而不是在返回棧的頂部建立新例項);或者,您希望在使用者離開任務時,清除返回棧中除根 Activity 以外的所有其他 Activity。這個時候您就要控制任務和返回棧了,那就得上任務管理了。

一般通過兩種方式來管理任務和返回棧:一是通過activity清單檔案launchMode啟動模式來管理,二是通過呼叫 startActivity() 時 Intent 中加入一個標誌來管理,用於宣告新 Activity 如何(或是否)與當前任務關聯。

2.1 activity清單檔案launchMode啟動模式

launchMode 屬性指定如何將 Activity 啟動到任務中的指令。您可以分配給 launchMode 屬性的啟動模式共有四種:

  • standard(預設模式)
           系統在啟動 Activity 的任務中建立 Activity 的新例項。Activity 可以多次例項化,而且每個例項均可屬於不同的任務(不同的taskAffinity,不同的應用)。所有啟動的Activity都會被加入到當前任務的返回棧中。

  • singleTop
           如果您要啟動的Activity已經位於返回棧的頂部的時候,則系統會通過呼叫該Activity的 onNewIntent() 方法向其傳送 Intent,而不是建立 Activity 的新例項。Activity 可以多次例項化(可以不是同一個應用的Activity)的前提是位於返回棧頂部的 Activity 並不是要啟動的Activity 。

這裡寫圖片描述

  • singleTask
           如果您要啟動的Activity已存在於一個單獨的任務中(不管是當前熱任務還是其他的任務只要他存在),則系統會通過呼叫現有例項的 onNewIntent() 方法向其傳送 Intent,而不是建立新例項。並且把該返回棧中該Activity之上的所有Activity彈出棧銷燬掉同時切換到你啟動的Activity的那個任務去。(同一個任務中的很好理解,我用圖來表示不用任務中singleTask的情況)。
    這裡寫圖片描述

  • singleInstance
           會把您要啟動的Activity單獨的放置在一個返回棧中,並且這個返回棧中只有這麼一個Activity。如果這個Activity啟動過(已經被放置在一個單獨的返回棧當中)則系統會通過呼叫現有例項的 onNewIntent() 方法向其傳送 Intent,而不是建立新例項。
    這裡寫圖片描述

2.2 Intent flag標誌:

  • FLAG_ACTIVITY_NEW_TASK:
           如果發起Activity和需要啟動的Activity都屬於同一個應用中(有相同的taskAffinity)。那麼表現形式和“singleTask”launcheMode相同(如果需要啟動的Activity之前已經被啟動過了,那麼需要啟動的Activity會轉到前臺,彈出任務回退棧該Activity上面所有的Activity。如果需要啟動的Activity沒有被啟動,則新建一個例項加入任務回退棧中)。
           如果發起Activity和需要啟動的Activity不屬於同一個應用中(不同的taskAffinity),那麼需要啟動的Activity會新建一個例項,並且加入到一個全新的任務回退棧中。

  • FLAG_ACTIVITY_SINGLE_TOP:
           表現形式和“singleTop”launcheMode相同。

  • FLAG_ACTIVITY_CLEAR_TOP:
           如果發起Activity和需要啟動的Activity都屬於同一個應用中(有相同的taskAffinity)。要啟動的Activity已經在當前回退棧中了,則會把該Activity和他之上的所有Activity銷燬掉,再重新例項化這個Activity,放入回退棧中。
           如果發起Activity和需要啟動的Activity不屬於同一個應用中(不同的taskAffinity),正常例項化Activity,放入當前回退棧中。

  • FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP:
           如果要啟動的Activity已經存在不管是在當前任務還是其他後臺任務中,都會把任務回退棧該Activity連同上面的所有Activity銷燬掉,再重新例項化Activity放入之前Activity存在的任務回退棧中。
    這裡寫圖片描述

三 處理任務關聯

“關聯”指示 Activity 優先屬於哪個任務。預設情況下,同一應用中的所有 Activity 彼此關聯屬於同一個任務。 因此,預設情況下,同一應用中的所有 Activity 優先位於相同任務中。 但是有的時候,您可能要修改 Activity 的預設關聯:在不同應用中定義的 Activity 可以共享關聯,或者可為在同一應用中定義的 Activity 分配不同的任務關聯。可以使用ManifestAndroid.xml檔案中activity標籤元素中的 taskAffinity 屬性修改任何給定 Activity 的關聯。

       affinity是指Activity的歸屬(Activity屬於哪個回退棧)。這個屬性表明Activity進入哪個回退棧當中去(注意這裡說的是進入哪個回退棧,只是)。如果想變成現實那麼的配合Intent flag的FLAG_ACTIVITY_NEW_TASK屬性或者allowTaskReparenting屬性來使用。

  • taskAffinity + Intent FLAG_ACTIVITY_NEW_TASK:
           如果要啟動的Activity和被啟動的Activity不屬於同一個taskAffinity,那麼被啟動的Activity會被放入一個新的任務返回棧中。

  • taskAffinity + allowTaskReparenting:
           把allowTaskReparenting屬性設定為true。Activity 可以從其啟動的任務棧移動到與其具有關聯的任務棧中(如果該任務出現在前臺)。簡單來說就是A應用啟動了B應用的一個介面,這個時候切回到B應用(HOME鍵再點選B的luancher圖示)這個時候這個頁面會抽出來移動到B應用回退棧的頂部。
    這裡寫圖片描述

四 清理返回棧

如果使用者長時間離開任務,則系統會清除所有 Activity 的任務,根 Activity 除外。 當使用者再次返回到任務時,僅恢復根Activity。系統這樣做的原因是,經過很長一段時間後,使用者可能已經放棄之前執行的操作,返回到任務是要開始執行新的操作。但是有的時候我們可以使用一些屬性來更改這些行為。

  • alwaysRetainTaskState:如果在任務的根 Activity 中將此屬性設定為 “true”,則不會發生剛才所述的預設行為。即使在很長一段時間後,任務仍將所有 Activity 保留在其堆疊中。

  • clearTaskOnLaunch:如果在任務的根 Activity 中將此屬性設定為 “true”,則每當使用者離開任務然後返回時,系統都會將堆疊清除到只剩下根 Activity。 換而言之,它與alwaysRetainTaskState 正好相反。 即使只離開任務片刻時間,使用者也始終會返回到任務的初始狀態。

  • finishOnTaskLaunch:此屬性類似於 clearTaskOnLaunch,但它對單個 Activity 起作用,而非整個任務。 此外,它還有可能會導致任何 Activity 停止,包括根 Activity。 設定為 “true” 時,Activity 仍是任務的一部分,但是僅限於當前會話。如果使用者離開然後返回任務,則任務將不復存在。

以上就是對Android任務和返回棧的簡單總結。

相關文章