理解任務(wù)和后臺堆棧(活動四)

任務(wù)是用戶在執(zhí)行特定作業(yè)時與之交互的活動的集合。
活動按堆棧排列 - (返回棧) - 按每個活動打開的順序排列。 例如,電子郵件應(yīng)用可能有一個活動來顯示新消息列表。 當用戶選擇消息時,將打開一個新活動以查看該消息。 此新活動將添加到后臺堆棧。 如果用戶按下“返回”按鈕,則表示新活動已完成并從堆棧中彈出。 以下視頻概述了后端堆棧的工作原理。
當應(yīng)用程序在多窗口環(huán)境中同時運行時,在Android 7.0(API級別24)及更高版本中受支持,系統(tǒng)會為每個窗口單獨管理任務(wù); 每個窗口可能有多個任務(wù)。 對于在Chromebook上運行的Android應(yīng)用程序也是如此:系統(tǒng)基于每個窗口管理任務(wù)或任務(wù)組。
設(shè)備主屏幕是大多數(shù)任務(wù)的起始位置。 當用戶觸摸應(yīng)用程序啟動器中的圖標(或主屏幕上的快捷方式)時,該應(yīng)用程序的任務(wù)將進入前臺。 如果應(yīng)用程序不存在任務(wù)(最近未使用該應(yīng)用程序),則會創(chuàng)建一個新任務(wù),該應(yīng)用程序的“主”活動將作為堆棧中的根活動打開。
當前活動從另一個活動開始時,新活動將被推到堆棧頂部并獲得焦點。 之前的活動仍在堆棧中,但已停止。 當活動停止時,系統(tǒng)將保留其用戶界面的當前狀態(tài)。 當用戶按下“返回”按鈕時,當前活動將從堆棧頂部彈出(活動被銷毀),之前的活動將恢復(fù)(其UI的先前狀態(tài)將恢復(fù))。 堆棧中的活動永遠不會重新排列,只能在當前活動啟動時從堆棧中推送并彈出到堆棧中,并在用戶使用“返回”按鈕離開時彈出。 因此,后堆棧作為“后進先出”對象結(jié)構(gòu)操作。 圖1顯示了這種行為,時間軸顯示了活動之間的進度以及每個時間點的當前后棧。

圖片1.png

圖1.表示任務(wù)中的每個新活動如何將項添加到后臺堆棧。 當用戶按下“返回”按鈕時,將破壞當前活動并恢復(fù)先前的活動。

如果用戶繼續(xù)按Back,則彈出堆棧中的每個活動以顯示前一個活動,直到用戶返回主屏幕(或任務(wù)開始時運行的任何活動)。 從堆棧中刪除所有活動后,該任務(wù)不再存在。

任務(wù)是一個內(nèi)聚單元,當用戶開始新任務(wù)或通過主頁按鈕進入主屏幕時,可以移動到“后臺”。在后臺,任務(wù)中的所有活動都會停止,但任務(wù)的后臺堆棧保持不變 - 任務(wù)在發(fā)生另一項任務(wù)時完全失去焦點,如圖2所示。然后任務(wù)可以返回到“前臺“所以用戶可以從中斷的地方繼續(xù)前進。例如,假設(shè)當前任務(wù)(任務(wù)A)在其堆棧中有三個活動 - 在當前活動下有兩個活動。用戶按下主頁按鈕,然后從應(yīng)用啟動器啟動新應(yīng)用。出現(xiàn)主屏幕時,任務(wù)A進入后臺。當新應(yīng)用程序啟動時,系統(tǒng)會使用自己的一系列活動為該應(yīng)用程序(任務(wù)B)啟動任務(wù)。在與該應(yīng)用程序交互之后,用戶再次返回Home并選擇最初啟動任務(wù)A的應(yīng)用程序?,F(xiàn)在,任務(wù)A進入前臺 - 其堆棧中的所有三個活動都完好無損,并且堆棧頂部的活動將恢復(fù)。此時,用戶還可以通過返回主頁并選擇啟動該任務(wù)的應(yīng)用程序圖標(或從“最近”屏幕中選擇應(yīng)用程序的任務(wù))切換回任務(wù)B.這是Android上的多任務(wù)處理的一個示例。


圖片2.png

圖2.兩個任務(wù):任務(wù)B在前臺接收用戶交互,而任務(wù)A在后臺,等待恢復(fù)。

圖片3.png

圖3.單個活動多次實例化。

注意:可以在后臺同時保存多個任務(wù)。 但是,如果用戶同時運行許多后臺任務(wù),系統(tǒng)可能會開始銷毀后臺活動以恢復(fù)內(nèi)存,從而導(dǎo)致活動狀態(tài)丟失。

由于后備堆棧中的活動永遠不會重新排列,如果您的應(yīng)用程序允許用戶從多個活動啟動特定活動,則會創(chuàng)建該活動的新實例并將其推送到堆棧(而不是帶來任何先前的活動實例) 到頂部)。 因此,您的應(yīng)用中的一個活動可能會被多次實例化(甚至來自不同的任務(wù)),如圖3所示。因此,如果用戶使用“后退”按鈕向后導(dǎo)航,則活動的每個實例都按順序顯示 被打開(每個都有自己的UI狀態(tài))。 但是,如果您不希望多次實例化活動,則可以修改此行為。 有關(guān)如何執(zhí)行此操作將在后面的“管理任務(wù)”一節(jié)中討論。

總結(jié)活動和任務(wù)的默認行為:

  • 當活動A啟動活動B時,活動A停止,但系統(tǒng)保留其狀態(tài)(例如滾動位置和輸入到表單中的文本)。 如果用戶在活動B中按下“返回”按鈕,則活動A將恢復(fù)其狀態(tài)。
  • 當用戶通過按Home鍵離開任務(wù)時,當前活動將停止,其任務(wù)將進入后臺。 系統(tǒng)保留任務(wù)中每個活動的狀態(tài)。 如果用戶稍后通過選擇開始任務(wù)的啟動器圖標來恢復(fù)任務(wù),則任務(wù)將到達前臺并恢復(fù)堆棧頂部的活動。
  • 如果用戶按下“返回”按鈕,則會從堆棧中彈出當前活動并將其銷毀。 堆棧中先前的活動已恢復(fù)。 當活動被銷毀時,系統(tǒng)不會保留活動的狀態(tài)。
  • 活動可以多次實例化,甚至可以從其他任務(wù)實例化。

導(dǎo)航設(shè)計
有關(guān)Android導(dǎo)航如何在Android上運行的更多信息,請閱讀Android Design的導(dǎo)航指南。

一、管理任務(wù)

Android管理任務(wù)和后臺堆棧的方式,如上所述 - 通過將所有活動連續(xù)啟動到同一任務(wù)和“后進先出”堆棧 - 對于大多數(shù)應(yīng)用程序而言非常有用,您不必擔心 關(guān)于您的活動如何與任務(wù)相關(guān)聯(lián)或它們?nèi)绾未嬖谟诤笈_堆棧中。 但是,您可能決定要中斷正常行為。 也許您希望應(yīng)用程序中的活動在啟動時開始新任務(wù)(而不是放在當前任務(wù)中); 或者,當你開始一個活動時,你想要提出它的現(xiàn)有實例(而不是在后面的堆棧頂部創(chuàng)建一個新的實例); 或者,您希望在用戶離開任務(wù)時清除除了根活動之外的所有活動的后臺堆棧。
您可以使用<activity>清單元素中的屬性以及傳遞給startActivity()的intent中的標記來執(zhí)行這些操作。

在這方面,您可以使用的主要<activity>屬性是:

  • taskAffinity
  • launchMode
  • allowTaskReparenting
  • clearTaskOnLaunch
  • alwaysRetainTaskState
  • finishOnTaskLaunch

您可以使用的主要意圖標志是:

  • FLAG_ACTIVITY_NEW_TASK
  • FLAG_ACTIVITY_CLEAR_TOP
  • FLAG_ACTIVITY_SINGLE_TOP

在以下部分中,您將了解如何使用這些清單屬性和意圖標志來定義活動與任務(wù)的關(guān)聯(lián)方式以及它們在后端堆棧中的行為方式。

另外,單獨討論的是在“最近”屏幕中如何表示和管理任務(wù)和活動的注意事項。 有關(guān)詳細信息,請參閱最近屏幕。 通常,您應(yīng)該允許系統(tǒng)在“最近”屏幕中定義您的任務(wù)和活動的表示方式,而不需要修改此行為。

警告:大多數(shù)應(yīng)用程序不應(yīng)該中斷活動和任務(wù)的默認行為。 如果您確定您的活動需要修改默認行為,請謹慎使用,并確保在啟動期間以及使用“返回”按鈕從其他活動和任務(wù)導(dǎo)航回活動時測試活動的可用性。 請務(wù)必測試可能與用戶預(yù)期行為沖突的導(dǎo)航行為。

1、定義啟動模式

啟動模式允許您定義活動的新實例與當前任務(wù)的關(guān)聯(lián)方式。 您可以通過兩種方式定義不同的啟動模式:

  • Using the manifest file
    在清單文件中聲明活動時,可以指定活動在啟動時應(yīng)如何與任務(wù)關(guān)聯(lián)。
  • Using Intent flags
    當您調(diào)用startActivity()時,您可以在Intent中包含一個標志,該標志聲明新活動應(yīng)如何(或是否)與當前任務(wù)關(guān)聯(lián)。

因此,如果活動A啟動活動B,活動B可以在其清單中定義它應(yīng)該如何與當前任務(wù)相關(guān)聯(lián)(如果有的話),活動A也可以請求活動B應(yīng)該如何與當前任務(wù)相關(guān)聯(lián)。 如果兩個活動都定義了活動B應(yīng)該如何與任務(wù)相關(guān)聯(lián),則活動A的請求(如意圖中所定義)將遵循活動B的請求(如其清單中所定義)。

注意:清單文件可用的某些啟動模式不可用作intent的標志,同樣,某些啟用模式可用作intent的標志,無法在清單中定義。

a、使用清單文件

在清單文件中聲明活動時,可以使用<activity>元素的launchMode屬性指定活動應(yīng)如何與任務(wù)關(guān)聯(lián)。

launchMode屬性指定有關(guān)如何將活動啟動到任務(wù)的說明。 您可以為launchMode屬性分配四種不同的啟動模式:
"standard" (the default mode)
默認。 系統(tǒng)在啟動它的任務(wù)中創(chuàng)建活動的新實例,并將意圖路由到該實例。 活動可以多次實例化,每個實例可以屬于不同的任務(wù),一個任務(wù)可以有多個實例。

"singleTop"
果活動的實例已存在于當前任務(wù)的頂部,則系統(tǒng)通過調(diào)用其onNewIntent()方法將意圖路由到該實例,而不是創(chuàng)建活動的新實例?;顒涌梢远啻螌嵗?,每個實例可以屬于不同的任務(wù),一個任務(wù)可以有多個實例(但只有當后端堆棧頂部的活動不是活動的現(xiàn)有實例時)。
例如,假設(shè)任務(wù)的后向堆棧由根活動A組成,活動B,C和D位于頂部(堆棧為A-B-C-D; D位于頂部)。意圖到達類型D的活動。如果D具有默認的“標準”啟動模式,則啟動該類的新實例并且堆棧變?yōu)锳-B-C-D-D。但是,如果D的啟動模式是“singleTop”,則現(xiàn)有的D實例通過onNewIntent()接收意圖,因為它位于堆棧的頂部 - 堆棧仍然是A-B-C-D。但是,如果意圖到達類型B的活動,則即使其啟動模式為“singleTop”,也會將新的B實例添加到堆棧中。

注意:創(chuàng)建活動的新實例時,用戶可以按“返回”按鈕返回上一個活動。 但是,當活動的現(xiàn)有實例處理新意圖時,在新意圖到達onNewIntent()之前,用戶無法按“返回”按鈕返回活動狀態(tài)。

"singleTask"
系統(tǒng)創(chuàng)建新任務(wù)并在新任務(wù)的根目錄下實例化活動。 但是,如果活動的實例已存在于單獨的任務(wù)中,則系統(tǒng)會通過調(diào)用其onNewIntent()方法將意圖路由到現(xiàn)有實例,而不是創(chuàng)建新實例。 一次只能存在一個活動實例。

注意:雖然活動在新任務(wù)中啟動,但“后退”按鈕仍會將用戶返回到上一個活動。

"singleInstance"
與“singleTask”相同,但系統(tǒng)不會在持有實例的任務(wù)中啟動任何其他活動。 活動始終是其任務(wù)的唯一成員; 任何由此開始的活動都在一個單獨的任務(wù)中打開。

作為另一個示例,Android瀏覽器應(yīng)用程序聲明Web瀏覽器活動應(yīng)始終在其自己的任務(wù)中打開 - 通過在<activity>元素中指定singleTask啟動模式。這意味著,如果您的應(yīng)用發(fā)出打開Android瀏覽器的意圖,則其活動不會與您的應(yīng)用放在同一任務(wù)中。相反,要么為瀏覽器啟動新任務(wù),要么如果瀏覽器已經(jīng)在后臺運行任務(wù),則該任務(wù)將被提前處理新意圖。

無論活動是在新任務(wù)中啟動還是在與啟動它的活動相同的任務(wù)中啟動,“返回”按鈕始終會將用戶帶到上一個活動。但是,如果啟動指定singleTask啟動模式的活動,則如果后臺任務(wù)中存在該活動的實例,則將整個任務(wù)帶到前臺。此時,后端堆棧現(xiàn)在包括堆棧頂部提出的任務(wù)中的所有活動。圖4說明了這種情況。


圖片4.png

圖4.表示如何將具有啟動模式“singleTask”的活動添加到后臺堆棧。 如果活動已經(jīng)是具有自己的后臺堆棧的后臺任務(wù)的一部分,那么整個后臺堆棧也會在當前任務(wù)的基礎(chǔ)上出現(xiàn)。

有關(guān)在清單文件中使用啟動模式的更多信息,請參閱<activity>元素文檔,其中詳細討論了launchMode屬性和接受的值。

注意:您使用launchMode屬性為活動指定的行為可以被啟動活動的intent所包含的標記覆蓋,如下一節(jié)中所述。

b、使用Intent標志

啟動活動時,您可以通過在傳遞給startActivity()的intent中包含標志來修改活動與其任務(wù)的默認關(guān)聯(lián)。 您可以用來修改默認行為的標志是:

FLAG_ACTIVITY_NEW_TASK

在新任務(wù)中啟動活動。 如果任務(wù)已在為您正在啟動的活動運行,則該任務(wù)將返回到前臺,并恢復(fù)其上一個狀態(tài),并且活動將在onNewIntent()中接收新的意圖。

這會產(chǎn)生與上一節(jié)中討論的“singleTask”launchMode值相同的行為。

FLAG_ACTIVITY_SINGLE_TOP

如果正在啟動的活動是當前活動(在后臺堆棧的頂部),則現(xiàn)有實例將接收對onNewIntent()的調(diào)用,而不是創(chuàng)建活動的新實例。

這會產(chǎn)生與上一節(jié)中討論的“singleTop”launchMode值相同的行為。

FLAG_ACTIVITY_CLEAR_TOP

如果正在啟動的活動已在當前任務(wù)中運行,則不會啟動該活動的新實例,而是銷毀其上的所有其他活動,并將此意圖傳遞給活動的恢復(fù)實例(現(xiàn)在開啟) top),通過onNewIntent())。

生成此行為的launchMode屬性沒有任何值。

FLAG_ACTIVITY_CLEAR_TOP通常與FLAG_ACTIVITY_NEW_TASK結(jié)合使用。 當一起使用時,這些標志是一種在另一個任務(wù)中定位現(xiàn)有活動并將其置于可以響應(yīng)意圖的位置的方法。

注意:如果指定活動的啟動模式是“標準”,它也會從堆棧中刪除,并在其位置啟動一個新實例來處理傳入的意圖。 這是因為當啟動模式為“標準”時,總是為新意圖創(chuàng)建新實例。

2、處理親和力

親和力指示活動喜歡屬于哪個任務(wù)。 默認情況下,同一應(yīng)用程序中的所有活動都具有彼此的關(guān)聯(lián)。 因此,默認情況下,同一個應(yīng)用程序中的所有活動都希望處于同一任務(wù)中。 但是,您可以修改活動的默認關(guān)聯(lián)。 在不同應(yīng)用中定義的活動可以共享親和力,或者可以為同一應(yīng)用中定義的活動分配不同的任務(wù)親和力。
您可以使用<activity>元素的taskAffinity屬性修改任何給定活動的親緣關(guān)系。
taskAffinity屬性采用字符串值,該值必須與<manifest>元素中聲明的默認包名稱唯一,因為系統(tǒng)使用該名稱來標識應(yīng)用程序的默認任務(wù)關(guān)聯(lián)。
親和力在兩種情況下起作用:

  • 當啟動活動的intent包含F(xiàn)LAG_ACTIVITY_NEW_TASK標志時。
    默認情況下,新活動將啟動到調(diào)用startActivity()的活動的任務(wù)中。它被調(diào)到與調(diào)用者相同的后棧。但是,如果傳遞給startActivity()的intent包含F(xiàn)LAG_ACTIVITY_NEW_TASK標志,則系統(tǒng)會查找另一個任務(wù)以容納新活動。通常,這是一項新任務(wù)。但是,它不一定是。如果已存在與新活動具有相同親緣關(guān)系的現(xiàn)有任務(wù),則會將活動啟動到該任務(wù)中。如果沒有,它開始一項新任務(wù)。
    如果此標志導(dǎo)致活動開始新任務(wù),并且用戶按下主頁按鈕以離開它,則必須有某種方式讓用戶導(dǎo)航回任務(wù)。某些實體(例如通知管理器)總是在外部任務(wù)中啟動活動,從不作為自己的一部分,因此它們總是將FLAG_ACTIVITY_NEW_TASK置于它們傳遞給startActivity()的意圖中。如果您有可以由可能使用此標志的外部實體調(diào)用的活動,請注意用戶有一種獨立的方式返回已啟動的任務(wù),例如使用啟動器圖標(任務(wù)的根活動)有一個CATEGORY_LAUNCHER意圖過濾器;請參閱下面的“啟動任務(wù)”部分。
  • 當一個活動的allowTaskReparenting屬性設(shè)置為“true”時。
    在這種情況下,當該任務(wù)到達前臺時,活動可以從它開始的任務(wù)移動到它具有親和力的任務(wù)。
    例如,假設(shè)在所選城市中報告天氣狀況的活動被定義為旅行應(yīng)用程序的一部分。 它與同一應(yīng)用程序中的其他活動(默認應(yīng)用程序關(guān)聯(lián))具有相同的親和力,并允許使用此屬性重新生成父項。 當您的某個活動啟動天氣報告者活動時,它最初屬于與您的活動相同的任務(wù)。 但是,當旅行應(yīng)用程序的任務(wù)到達前臺時,天氣報告者活動將重新分配給該任務(wù)并顯示在其中。

提示:如果APK文件從用戶的角度包含多個“app”,您可能希望使用taskAffinity屬性為與每個“app”關(guān)聯(lián)的活動分配不同的親和力。

3、清理后棧

如果用戶長時間離開任務(wù),系統(tǒng)將清除除根活動之外的所有活動的任務(wù)。 當用戶再次返回任務(wù)時,僅還原根活動。 系統(tǒng)以這種方式運行,因為在很長一段時間之后,用戶可能已經(jīng)放棄了之前正在做的事情并返回任務(wù)以開始新的事情。

您可以使用一些活動屬性來修改此行為:
alwaysRetainTaskState:
如果在任務(wù)的根活動中將此屬性設(shè)置為“true”,則不會發(fā)生剛才描述的默認行為。 即使經(jīng)過很長一段時間,任務(wù)仍會保留堆棧中的所有活動。

clearTaskOnLaunch:
如果在任務(wù)的根活動中將此屬性設(shè)置為“true”,則只要用戶離開任務(wù)并返回到該任務(wù),就會將堆棧清除為根活動。 換句話說,它與alwaysRetainTaskState相反。 即使在離開任務(wù)片刻之后,用戶也始終以初始狀態(tài)返回任務(wù)。

finishOnTaskLaunch:
此屬性類似于clearTaskOnLaunch,但它在單個活動上運行,而不是整個任務(wù)。 它還可以導(dǎo)致任何活動消失,包括根活動。 當它設(shè)置為“true”時,活動仍然是當前會話的任務(wù)的一部分。 如果用戶離開然后返回任務(wù),它將不再存在。

4、開始一項任務(wù)

您可以將活動設(shè)置為任務(wù)的入口點,方法是為其指定一個過濾器,其中“android.intent.action.MAIN”作為指定的操作,“android.intent.category.LAUNCHER”作為指定的類別。 例如:

<activity ... >
    <intent-filter ... >
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    ...
</activity>

這種意圖過濾器會導(dǎo)致活動的圖標和標簽顯示在應(yīng)用程序啟動器中,從而為用戶提供啟動活動并返回其在啟動后隨時創(chuàng)建的任務(wù)的方法。
第二種能力很重要:用戶必須能夠離開任務(wù),然后使用此活動啟動器返回該任務(wù)。因此,僅當活動具有ACTION_MAIN和CATEGORY_LAUNCHER過濾器時,才應(yīng)使用將活動標記為始終啟動任務(wù)的兩種啟動模式“singleTask”和“singleInstance”。例如,想象一下,如果缺少過濾器會發(fā)生什么:intent會啟動“singleTask”活動,啟動新任務(wù),并且用戶會花一些時間在該任務(wù)中工作。然后用戶按下主頁按鈕。該任務(wù)現(xiàn)在發(fā)送到后臺并且不可見。現(xiàn)在用戶無法返回任務(wù),因為它未在應(yīng)用啟動器中顯示。

對于您不希望用戶能夠返回活動的情況,請將<activity>元素的finishOnTaskLaunch設(shè)置為“true”(請參閱??清除后臺堆棧)。

有關(guān)如何在“概述”屏幕中表示和管理任務(wù)和活動的更多信息,請參見“最近用戶”屏幕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • 一、Python簡介和環(huán)境搭建以及pip的安裝 4課時實驗課主要內(nèi)容 【Python簡介】: Python 是一個...
    _小老虎_閱讀 6,331評論 0 10
  • 陽光照在臉上 我慵懶的睜開眼睛 望著那古舊的屋頂 想著漫長的歲月 冷風吹進 即使那厚厚的毛毯 也不能抵擋那凄冷的氛...
    南途丶閱讀 257評論 0 0
  • 我最喜歡看雜志上的愛情故事,聽別人家的愛情經(jīng)歷,可是就像別人家的孩子一樣,好像永遠經(jīng)歷不到自己的頭上。 沒有美好而...
    夏林鹿閱讀 490評論 0 0
  • 一、用思維導(dǎo)圖拆解10W+文章《你的死工資,正在拖垮你》的結(jié)構(gòu)框架 第三課的作業(yè),是要畫思維導(dǎo)圖,正好布置在我最忙...
    水輕揚閱讀 342評論 1 1

友情鏈接更多精彩內(nèi)容