<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ### Google官網文章任務和返回棧《摘抄》 一個 Activity 甚至可以啟動設備上其他應用中存在的 Activity,例如,如果應用想要發送電子郵件,則可將 Intent 定義為執行“發送”操作并加入一些數據,如電子郵件地址和電子郵件。 然后,系統將打開其他應用中聲明自己處理此類 Intent 的 Activity。在這種情況下,Intent 是要發送電子郵件,因此將啟動電子郵件應用的“撰寫”Activity(如果多個 Activity 支持相同 Intent,則系統會讓用戶選擇要使用的 Activity)。發送電子郵件時,Activity 將恢復,看起來好像電子郵件 Activity 是您的應用的一部分。 **即使這兩個 Activity 可能來自不同的應用,但是 Android 仍會將 Activity 保留在相同的任務中,以維護這種無縫的用戶體驗。** **任務是指在執行特定作業時與用戶交互的一系列 Activity。 這些 Activity 按照各自的打開順序排列在堆棧(即返回棧)中。** >[info] **注意**: 可以在Activity的onCreate()方法中調用getTaskId()方法(該方法內部調用了類ActivityManagerService的getTaskForActivity方法,而getTaskForActivity這個方法內部又調用了ActivityRecord.getTaskForActivityLocked()方法)得出該Activity所在的棧的ID **當前 Activity(標記為Activity①)** 啟動**另一個 Activity(標記為Activity②)** 時,該新 Activity(**Activity②**) 會被推送到堆棧頂部,成為焦點所在。 前一個 Activity(**Activity①**) **仍保留在堆棧中,但是處于停止狀態**。**Activity(就是指Activity,不管是Activity①還是Activity②) 停止時,系統會保持其用戶界面的當前狀態**。 用戶按“返回”按鈕時,當前 Activity(**Activity②**) 會從堆棧頂部彈出(Activity(**Activity②**) 被銷毀),而前一個 Activity(**Activity①**) 恢復執行(恢復其 UI 的前一狀態)。 >[info]**總結**: 堆棧中的 Activity 永遠不會重新排列,僅推入和彈出堆棧:由當前 Activity 啟動時推入堆棧;用戶使用“返回”按鈕退出時彈出堆棧。 因此,返回棧以“后進先出”對象結構運行。 ![](https://box.kancloud.cn/2015-12-01_565da698aaae5.jpg) 圖 1 通過時間線顯示 Activity 之間的進度以及每個時間點的當前返回棧,直觀呈現了這種行為。 圖解:棧stack中原先只有Activity 1 ,之后Activity 1啟動Activity 2,棧stack中有Activity 1 和Activity 2,Activity 1 處于停止狀態,Activity 2處于活動狀態;后來Activity 2又啟動了Activity 3,那Activity 3處于活動狀態,Activity 2 和Activity 1處于停止狀態; 之后按下導航的返回鍵或者調用了finish()方法后,處于棧頂的Activity 3被彈出,Activity 2又處于棧頂,處于活動狀態。這也就印證了**棧的后進先出**的思想 。如果用戶繼續按“返回”,堆棧中的相應 Activity 就會被彈出,以顯示前一個 Activity,直到用戶返回主屏幕為止(或者,返回任務開始時正在運行的任意 Activity)。 當所有 Activity 均從堆棧中移除后,任務即不復存在。任務棧是一種“后進先出”的棧結構,這個比較好理解,每按一下back 鍵就會有一個Activity 出棧,直到棧空為止,當棧中無任何Activity的時候,系統就會回收這個任務棧。 ### Android 多任務運行機制 ![](https://box.kancloud.cn/2015-12-01_565da699b8109.jpg) 圖 2. 兩個任務:任務 B 在前臺接收用戶交互,而任務 A 則在后臺等待恢復。 任務(Task1)是一個有機整體,當用戶開始新任務(Task2)或通過“主頁”按鈕(Home鍵)轉到主屏幕時,可以將該任務(Task1)移動到“后臺”。 盡管在后臺時,該任務(Task1)中的所有 Activity 全部停止,但是任務(Task1)的返回棧仍舊不變,也就是說,**當另一個任務(Task2)發生時,該任務(Task1)僅僅失去焦點而已**,如圖 2 中所示。然后,任務(Task1)可以返回到“前臺”,用戶就能夠回到離開時的狀態。 例如,假設當前任務(任務 A)的堆棧中有三個 Activity,即當前 Activity 下方還有兩個 Activity。 用戶先按“主頁”按鈕(Home鍵),然后從應用啟動器啟動新應用。 顯示主屏幕時,任務 A 進入后臺。**新應用啟動時,系統會使用自己的 Activity 堆棧為該應用啟動一個任務(任務 B)**。與該應用交互之后,用戶再次返回主屏幕并選擇最初啟動任務 A 的應用。現在,任務 A 出現在前臺,其堆棧中的所有三個 Activity 保持不變,而位于堆棧頂部的 Activity 則會恢復執行。 此時,用戶還可以通過轉到主屏幕并選擇啟動該任務的應用圖標(或者,通過從概覽屏幕選擇該應用的任務)切換回任務 B。這是 Android 系統中的一個多任務示例。 >[warning] **注意**:**后臺可以同時運行多個任務。但是,如果用戶同時運行多個后臺任務,則系統可能會開始銷毀后臺 Activity,以回收內存資源,從而導致 Activity 狀態丟失**。請參閱下面有關 [Activity 狀態](https://developer.android.com/guide/components/tasks-and-back-stack.html#ActivityState)的部分。 Activity 和任務的默認行為總結如下: 1. 當 Activity A 啟動 Activity B 時,Activity A 將會停止,但系統會保留其狀態(例如,滾動位置和已輸入表單中的文本)。如果用戶在處于 Activity B 時按“返回”按鈕,則 Activity A 將恢復其狀態,繼續執行。 2. 用戶通過按“主頁”按鈕(Home鍵)離開任務時,當前 Activity 將停止且其任務會進入后臺。 系統將保留任務中每個 Activity 的狀態。如果用戶稍后通過選擇開始任務的啟動器圖標來恢復任務,則任務將出現在前臺并恢復執行堆棧頂部的 Activity。 3. 如果用戶按“返回”按鈕,則當前 Activity(處于棧頂的那個Activity即上面1中的ActivityB) 會從堆棧彈出并被銷毀。 堆棧中的前一個 Activity(Activity A) 恢復執行。銷毀 Activity 時,系統不會保留該 Activity 的狀態。 4. 即使來自其他任務,Activity 也可以多次實例化。(但是多次實例化,會造成內存資源浪費,具體可參考下面) #### 一個 Activity 將多次實例化 ![](https://box.kancloud.cn/2015-12-01_565da69aa2484.jpg) 圖 3. 一個 Activity 將多次實例化。 由于**返回棧中的 Activity 永遠不會重新排列**,因此如果應用允許用戶從多個 Activity 中啟動特定 Activity,則會創建該 Activity 的新實例并推入堆棧中(而不是將 Activity 的任一先前實例置于頂部)。 因此,**應用中的一個 Activity 可能會多次實例化(即使 Activity 來自不同的任務)**,如圖 3 所示。因此,如果用戶使用“返回”按鈕向后導航,則會按 Activity 每個實例的打開順序顯示這些實例(每個實例的 UI 狀態各不相同)。 但是,如果您不希望 Activity 多次實例化,則可修改此行為。 具體操作方法將在后面的管理任務部分中討論。 ### 保存 Activity 狀態 正如上文所述,當 Activity 停止時,系統的默認行為會保留其狀態。 這樣一來,當用戶導航回到上一個 Activity 時,其用戶界面與用戶離開時一樣。**但是,在 Activity 被銷毀且必須重建時,您可以而且應當主動使用回調方法保留 Activity 的狀態。** 系統停止您的一個 Activity 時(例如,新 Activity 啟動或任務轉到前臺(即重新開始一個新的任務)),**如果系統需要回收系統內存資源,則可能會完全銷毀該 Activity。 發生這種情況時,有關該 Activity 狀態的信息將會丟失。如果發生這種情況,系統仍會知道該 Activity 存在于返回棧中,但是當該 Activity 被置于堆棧頂部時,系統一定會重建 Activity(而不是恢復 Activity)**。 **為了避免用戶的工作丟失,您應主動通過在 Activity 中實現 [onSaveInstanceState()](https://developer.android.com/reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle)) 回調方法來保留工作**。 如需了解有關如何保存 Activity 狀態的詳細信息,請參閱 [Activity](https://developer.android.com/guide/components/activities.html#SavingActivityState) 文檔。 ### 管理任務 >[info] **情景**: Android 管理任務和返回棧的方式(如上所述,即:將所有連續啟動的 Activity 放入同一任務和“后進先出”堆棧中)非常適用于大多數應用,而您不必擔心 Activity 如何與任務關聯或者如何存在于返回棧中(也可以自定義設置)。 >但是,您可能會決定要中斷正常行為。 >也許您希望應用中的 Activity 在啟動時開始新任務(而不是放置在當前任務中); >或者,當啟動 Activity 時,您希望將其現有實例上移一層(而不是在返回棧的頂部創建新實例); >或者,您希望在用戶離開任務時,清除返回棧中除根 Activity 以外的所有其他 Activity。 通過使用 `<activity>` 清單文件元素中的屬性和傳遞給 [startActivity()](https://developer.android.com/reference/android/app/Activity.html#startActivity(android.content.Intent)) 的 Intent 中的標志,您可以執行所有這些操作以及其他操作。 在這一方面,您可以使用的主要 `<activity>` 屬性包括: [taskAffinity](https://developer.android.com/guide/topics/manifest/activity-element.html#aff) [launchMode](https://developer.android.com/guide/topics/manifest/activity-element.html#lmode) [allowTaskReparenting](https://developer.android.com/guide/topics/manifest/activity-element.html#reparent) [clearTaskOnLaunch](https://developer.android.com/guide/topics/manifest/activity-element.html#clear) [alwaysRetainTaskState](https://developer.android.com/guide/topics/manifest/activity-element.html#always) [finishOnTaskLaunch](https://developer.android.com/guide/topics/manifest/activity-element.html#finish) 您可以使用的主要 Intent 標志包括: [FLAG_ACTIVITY_NEW_TASK](https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_NEW_TASK) [FLAG_ACTIVITY_CLEAR_TOP](https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_CLEAR_TOP) [FLAG_ACTIVITY_SINGLE_TOP](https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_SINGLE_TOP) 在下文中,您將了解如何使用這些清單文件屬性和 Intent 標志定義 Activity 與任務的關聯方式,以及 Activity 在返回棧中的行為方式。 此外,我們還單獨介紹了有關如何在概覽屏幕中顯示和管理任務與 Activity 的注意事項。 如需了解詳細信息,請參閱[概覽屏幕](https://developer.android.com/guide/components/recents.html)。 通常,您應該允許系統定義任務和 Activity 在概覽屏幕中的顯示方法,并且無需修改此行為。 >[warning] **注意**:大多數應用都不得中斷 Activity 和任務的默認行為: 如果確定您的 Activity 必須修改默認行為,當使用“返回”按鈕從其他 Activity 和任務導航回到該 Activity 時,請務必要謹慎并確保在啟動期間測試該 Activity 的可用性。請確保測試導航行為是否有可能與用戶的預期行為沖突。 ### 定義啟動模式 啟動模式允許您定義 Activity 的新實例如何與當前任務關聯。 您可以通過兩種方法定義不同的啟動模式: 1. [使用清單文件](https://developer.android.com/guide/components/tasks-and-back-stack.html#ManifestForTasks) 在清單文件中聲明 Activity 時,您可以指定 Activity 在啟動時應該如何與任務關聯。 2. [使用 Intent 標志](https://developer.android.com/guide/components/tasks-and-back-stack.html#IntentFlagsForTasks) 調用 [startActivity()](https://developer.android.com/reference/android/app/Activity.html#startActivity(android.content.Intent)) 時,可以在 [Inten](https://developer.android.com/reference/android/content/Intent.html)t 中加入一個標志(上面管理任務章節中的3種Intent的flag),用于聲明新 Activity 如何(或是否)與當前任務關聯。 >[info] **注**:某些適用于清單文件的啟動模式不可用作 Intent 標志,同樣,某些可用作 Intent 標志的啟動模式無法在清單文件中定義。 因此,如果 Activity A 啟動 Activity B,則 Activity B 可以在其清單文件中定義它應該如何與當前任務關聯(如果可能),并且 Activity A 還可以請求 Activity B 應該如何與當前任務關聯。如果這兩個 Activity(Activity A和Activity B) 均定義 Activity B 應該如何與任務關聯(可以一個在intent中,一個在清單文件中),則 Activity A 的請求(如 Intent 中所定義)優先級要高于 Activity B 的請求(如其清單文件中所定義)。 #### **使用清單文件(AndroidMainifest啟動模式)** 在清單文件中聲明 Activity 時,您可以使用 `<activity>` 元素的 [launchMode](https://developer.android.com/guide/topics/manifest/activity-element.html#lmode) 屬性指定 Activity 應該如何與任務關聯。 [launchMode](https://developer.android.com/guide/topics/manifest/activity-element.html#lmode) 屬性指定有關應如何將 Activity 啟動到任務中的指令。您可以分配給 launchMode 屬性的啟動模式共有四種: * **"standard"(默認模式)** 默認。系統在啟動 Activity 的任務中創建 Activity 的新實例并向其傳送 Intent。Activity 可以多次實例化,而每個實例均可屬于不同的任務,并且一個任務可以擁有多個實例。如果不指定Activity 的啟動模式,則使用這種方式啟動Activity。這種啟動模式每次都會創建新的實例,每次點擊standard 模式創建Activity 后,都會創建新的MainActivity 覆蓋在原Activity 上。 ![standard啟動模式](https://box.kancloud.cn/e55ae98a7de1dfa14b8af277990d2608_299x369.jpg) 被創建的實例的生命周期符合典型情況下Activity 的生命周期,如上節描述,它的onCreate 、onStart 、onResume 都會被調用;在這種模式下,誰啟動了這個Activity,那么這個Activity 就運行在啟動它的那個Activity所在的棧中。 >[warning] **注意**:當我們用ApplicationContext 去啟動standard 模式的Activity 的時候會報錯,錯誤如下: ~~~ E/AndroidRuntime(674): android.util.AndroidRuntimeException: Calling startActivity from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want? ~~~ 相信這句話讀者一定不陌生,這是因為standard 模式的Activity 默認會進入啟動它的Activity 所屬的任務找中,但是由于非Activity 類型的Context 〈如ApplicationContext )并沒有所謂的任務棧,所以這就有問題了。解決這個問題的方法是為待啟動Activity 指定FLAG_ACTIVlTY _NEW TASK 標記位,這樣啟動的時候就會為它創建一個新的任務棧,這個時候待啟動Activity 實際上是以singleTask 模式啟動的,讀者可以仔細體會。 * * * * * * **"singleTop"(棧頂復用模式)** 如果當前任務的頂部已存在 Activity 的一個實例,則系統會通過調用該實例的 [onNewIntent()](https://developer.android.com/reference/android/app/Activity.html#onNewIntent(android.content.Intent)) 方法向其傳送 Intent,通過此方法的參數我們可以取出當前請求的信息;而不是創建 Activity 的新實例。需要注意的是,這個Activity 的onCreate 、onStart 不會被系統調用,因為它井沒有發生改變。 Activity 可以多次實例化,而每個實例均可屬于不同的任務,并且一個任務可以擁有多個實例;這句話是正確的,但前提是**位于返回棧頂部的 Activity 并不是 Activity 的現有實例**,如果是Activity 的現有實例,而且啟動模式是**singleTop**,則不會多次實例化。 例如,假設任務的返回棧包含根 Activity A 以及 Activity B、C 和位于頂部的 D(堆棧是 A-B-C-D;D 位于頂部)。收到針對 D 類 Activity 的 Intent。如果 D 具有默認的 "standard" 啟動模式,則會啟動該類的新實例,且堆棧會變成 A-B-C-D-D。但是,如果 D 的啟動模式是 "singleTop",則 D 的現有實例會通過 [onNewIntent()](https://developer.android.com/reference/android/app/Activity.html#onNewIntent(android.content.Intent)) 接收 Intent,因為它位于堆棧的頂部;而堆棧仍為 A-B-C-D。但是,**如果收到針對 B 類 Activity 的 Intent,則會向堆棧添加 B 的新實例,即便其啟動模式為 "singleTop" 也是如此**,也就是說,**如果B沒有位于棧頂,即便B的啟動模式是"singleTop",在收到針對 B 類 Activity 的 Intent時,也會向堆棧添加 B 的新實例**。 >[info] **注**:為某個 Activity 創建新實例時,用戶可以按“返回”按鈕返回到前一個 Activity。 但是,當 Activity 的現有實例處理新 Intent 時,則在新 Intent 到達 [onNewIntent()](https://developer.android.com/reference/android/app/Activity.html#onNewIntent(android.content.Intent)) 之前,用戶無法按“返回”按鈕返回到 Activity 的狀態。 總結:這種模式通常適用于就收到消息后現實的界面,比如QQ接收到消息后彈出Activity,如果一次來了10條消息,總不能一次彈10個Activity。 * * * * * * **"singleTask"(棧內復用模式)** 系統創建新任務并實例化位于新任務底部的 Activity。但是,如果該 Activity 的一個實例已存在于一個單獨的任務中,則系統會通過調用現有實例的 onNewIntent() 方法向其傳送 Intent,而不是創建新實例。一次只能存在 Activity 的一個實例。 >[info]**注**:盡管 Activity 在新任務中啟動,但是用戶按“返回”按鈕仍會返回到前一個 Activity。 singleTask 模式與singlTop 模式類似,只不過singleTop 是檢測檢頂元素是否是需要啟動的Activity ,而singleTask 是檢測整個Activity 戰中是否存在當前需要啟動的Activity。如果存在, 則將該Activity 置于棧頂,并將該Activity 以上的Activity 都銷毀(由于singleTask 默認具有clearTop 的效果)。不過這里是指在同一個App 中啟動這個singleTask 的Activity,如果是其他程序以singleTask 模式來啟動這個Activity ,那么它將創建一個新的任務棧。不過這里有一點需要注意的是,如果啟動的模式為singleTask 的Activity 巳經在后臺一個任務棧中了,那么啟動后,而后臺的這個任務棧將一起被切換到到前臺。 舉例如下: 1. 比如目前任務棧S1 中的情況為ABC,這個時候Activity D 以singleTask 模式請求啟動,其所需要的任務棧為S2 ,由于S2 和D 的實例均不存在,所以系統會先創建任務棧S2 ,然后再創建D 的實例井將其入棧到S2 。 2. 另外一種情況,假設D 所需的任務棧為S1,其他情況如上面例子l 所示,那么由于S1 已經存在,所以系統會直接創建D的實例井將其入棧到S1。 3. 如果D 所需的任務棧為S1,并且當前任務棧S1 的情況為ADBC ,根據棧內復用的原則,此時D 不會重新創建,系統會把D 切換到棧頂并調用其onNewlntent 方法,同時由于singleTask 默認具有clearTop 的效果,會導致棧內所有在D 上面的Activity全部出棧,于是最終S1中的情況為AD。這一點比較特殊。 上面例子中所需要的任務棧,具體是指什么??可以下文中摘抄的Android開發藝術探討中內容 **總結**:使用這個模式創建的Activity不是在新的任務棧中被打開, 就是將已經打開的Activity切換到前臺,所以這種啟動模式通常可以用來退出整個應用: 將主Activity 設為singleTask 模式,然后在要退出的Activity 中轉到主Activity,從而將主Activity之上的Activity 都清除,然后重寫主Activity 的onNewIntent()方法,在方法中加上一行代碼finish(),將最后一個Activity 結束掉。 * * * * * * **"singleInstance(單實例模式)"** 與 "singleTask" 相同,只是系統不會將任何其他 Activity 啟動到包含實例的任務中。該 Activity 始終是其任務唯一僅有的成員;由此 Activity 啟動的任何 Activity 均在單獨的任務中打開。而且**代碼中不能實現相同的啟動模式效果。** 這是一種加強的singleTask模式,它除了具有singleTask模式的所有特性外,還加強了一點,那就是具有此種模式的Activity 只能單獨地位于一個任務棧中,換句話說,比如Activity A 是singlelnstance 模式, 當A 啟動后,系統會為它創建一個新的任務棧,然后A 獨自在這個新的任務找中,由于棧內復用的特性,后續的請求均不會創建新的Activity,除非這個獨特的任務棧被系統銷毀了。 singleInstance 這種啟動模式和使用的瀏覽器工作原理類似。在多個程序中訪問瀏覽器時 ,如果當前瀏覽器沒有打開,則打開瀏覽器,否則會在當前打開的瀏覽器中訪問。申明為singleInstance 的Activity 會出現在一個新的任務棧中,而該任務棧中只存在這一個Activity 。舉個例子米說,如果應用A 的任務棧中創建了MainActivity 實例,且啟動模式為singleInstance,如果應用B 也要激活MainActivity , 則不需要創建,兩個應用共享該Activity實例。這種啟動模式常用于需要與程序分離的界面,如在SetupWizard中調用緊急呼叫,就是使用這種啟動模式。 不同于以上3 種啟動模式,指定為singlelnstance 模式的活動會啟用一個新的返回找來管理這個活動(其實如果singleTask 模式指定了不同的taskAftinity ,也會啟動一個新的返回棧)。那么這樣做有什么意義呢? 想象以下場景,假設我們的程序中有一個活動是允許其他程序調用的,如果我們想實現其他程序和我們的程序可以共享這個活動的實例,應該如何實現呢? 使用前面3 種啟動模式肯定是做不到的,因為每個應用程序都會有自己的返回棧,同一個活動在不同的返回棧中入棧時必然是創建了新的實例。而使用singlelnstance 模式就可以解決這個問題,在這種模式下會有一個單獨的返回棧來管理這個活動,不管是哪個應用程序來訪問這個活動,都共用的同一個返回棧,也就解決了共享活動實例的問題。(具體事例可參考郭霖的第一行代碼中例子) * * * * * #### 總結及補充 上面介紹了幾種啟動模式,這里需要補充一種情況,我們假設目前有2 個任務棧,前臺任務棧的情況為AB ,而后臺任務棧的情況為CD ,這里假設CD 的啟動模式均為singleTask 。現在請求啟動D,那么整個后臺任務校都會被切換到前臺,這個時候整個后臺任務棧變成了ABCD。當用戶按back 鍵的時候,列表中的Activity 會一一出錢,如圖1-7 所示。如果不是請求啟動D 而是啟動C,那么情況就不一樣了,請看圖1-8 ,具體原因在本節后面會再進行詳細分析。 ![](https://box.kancloud.cn/60fb61f430b97af01c0927d2c29d37a3_601x468.jpg) ![](https://box.kancloud.cn/eccc7b43d2bddda26de64653bebb2cfc_553x574.jpg) * **什么是某個Activity所需要的任務棧**? 在singleTask 啟動模式中,多次提到某個Activity所需要的任務棧,什么是Activity 所需要的任務找呢?這要從一個參數說起: **TaskAffinity**,可以翻譯為**任務相關性,可以定義Activity 的親和關系**。 - TaskAffinity,這個參數在清單文件的`<activity>`標簽的的`android:taskAffinity="string"`,同時特也是類ActivityInfo的成員變量;它**標識了一個Activity 所需要的任務棧的名字**,**默認情況下,所有Activity所需的任務棧的名字為應用的包名**。當然,我們**可以為每個Activity 都單獨指定TaskAffinity屬性**,這個**屬性值必須不能和包名相同,否則就相當于沒有指定**。 - **TaskAffinity 屬性主要和singleTask 啟動模式或者allowTaskReparenting 屬性配對使用,在其他情況下沒有意義**。 - 另外,**任務棧分為前臺任務棧和后臺任務棧,后臺任務棧中的Activity 位于暫停狀態,用戶可以通過切換將后臺任務棧再次調到前臺。** - 當TaskAffinity 和singleTask 啟動模式配對使用的時候,它是具有該模式的Activity 的目前任務棧的名字,待啟動的Activity 會運行在名字和TaskAffinity 相同的任務棧中。 - 當TaskAffinity 和allowTaskReparenting 結合的時候,這種情況比較復雜,會產生特殊的效果。當一個應用A 啟動了應用B 的某個Activity 后,如果這個Activity 的allowTaskReparenting 屬性為true 的話,那么當應用B 被啟動后,此Activity 會直接從應用A 的任務棧轉移到應用B 的任務棧中。這還是很抽象,可看下面的例子以及解釋。 - **allowTaskReparenting**這個參數可以在`<application>`和`<activity>`標簽定義,具體含義是:當啟動 Activity 的任務接下來轉至前臺時,Activity 是否能從該任務轉移至與其有親和關系的任務 —“true”表示它可以轉移,“false”表示它仍須留在啟動它的任務處。如果未設置該屬性,則對 Activity 應用由 `<application>` 元素的相應 allowTaskReparenting 屬性設置的值。 **默認值**為“**false**”。 - **正常情況下,當 Activity 啟動時,會與啟動它的任務關聯,并在其整個生命周期中一直留在該任務處**。您可以利用該屬性強制 Activity 在其當前任務不再顯示時將其父項更改為與其有親和關系的任務。**該屬性通常用于使應用的 Activity 轉移至與該應用關聯的主任務**。 - **Activity 的親和關系由 taskAffinity 屬性定義**。 任務的親和關系通過讀取其根 Activity 的親和關系來確定。因此,按照定義,根 Activity 始終位于具有相同親和關系的任務之中。 由于**具有“singleTask”或“singleInstance”啟動模式的 Activity 只能位于任務的根,因此更改父項僅限于“standard”和“singleTop”模式。** - **舉例如下**:再具體點,比如現在有2 個應用A和B, A 啟動了B 的一個Activity C,然后按Home 鍵回到桌面,然后再單擊B 的桌面圖標,這個時候井不是啟動了B 的主Activity ,而是重新顯示了已經被應用A 啟動的Activity C,或者說, C 從A 的任務棧轉移到了B 的任務棧中。可以這么理解,由于A 啟動了C,這個時候C 只能運行在A 的任務棧中,但是C 屬于B 應用,正常情況下,它的Task.Affinity 值肯定不可能和A 的任務棧相同〈因為包名不同〉。所以,當B 被啟動后, B 會創建自己的任務棧,這個時候系統發現C 原本所想要的任務棧已經被創建了,所以就把C 從A 的任務棧中轉移過來了。 無論 Activity 是在新任務中啟動,還是在與啟動 Activity 相同的任務中啟動,用戶按“返回”按鈕始終會轉到前一個 Activity。 但是,如果啟動指定 singleTask 啟動模式的 Activity,則當某后臺任務中存在該 Activity 的實例時,整個任務都會轉移到前臺。此時,返回棧包括上移到堆棧頂部的任務中的所有 Activity。 圖 4 顯示了這種情況。 ![](https://box.kancloud.cn/9e1a6ba53c9f3cfd646b7f2c9ab879c4_550x309.png) 圖 4. 顯示如何將啟動模式為“singleTask”的 Activity 添加到返回棧。 如果 Activity 已經是某個擁有自己的返回棧的后臺任務的一部分,則整個返回棧也會上移到當前任務的頂部。 如需了解有關在清單文件中使用啟動模式的詳細信息,請參閱 `<activity> `元素文檔,其中更詳細地討論了 launchMode 屬性和可接受的值。 >[info] **注**:使用 launchMode 屬性為 Activity 指定的行為可由 Intent 附帶的 Activity 啟動標志替代,下文將對此進行討論。 #### **使用 Intent 標志** > 啟動 Activity 時,您可以通過在傳遞給 startActivity() 的 Intent 中加入相應的標志,修改 Activity 與其任務的默認關聯方式。 代碼如下: ~~~ Intent intent = new Intent(); intent.setClass(MainActivity.this, SecondActivity.class); intent . addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); ~~~ Activity 的Flags 有很多,這里主要分析一些比較常用的標記位。標記位的作用很多, - 設定Activity 的啟動模式,比如FLAG_ACTIVITY_NEW_TASK 和FLAG_ACTIVITY _SINGLE_ TOP 等: - 影響Activity 的運行狀態,比如FLAG_ACTIVITY_CLEAR_TOP 和FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 等。 下面主要介紹幾個比較常用的標記位,剩下的標記位讀者可以查看官方文檔去了解,**大部分情況下,我們不需要為Activity 指定標記位**,因此,對于標記位理解即可。在使用標記位的時候,要注意有些標記位是系統內部使用的,應用程序不需要去手動設置這些標記位以防出現問題。 - **FLAG_ACTIVITY_NEW_TASK** 在新任務中啟動 Activity。如果已為正在啟動的 Activity 運行任務,則該任務會轉到前臺并恢復其最后狀態,同時 Activity 會在 onNewIntent() 中收到新 Intent。 正如前文所述,這**會產生與 "singleTask"launchMode 值相同的行為**。 使用一個新的Task 來啟動一個Activity ,但啟動的每個Activity 都將在一個新的Task 中。該Flag 通常使用在從Service 中啟動Activity 的場景,由于在Service 中并不存在Activity 棧,所以使用該Flag來創建一個新的Activity 棧,井創建新的Activity實例。 - **FLAG_ACTIVITY_SINGLE_TOP** 如果正在啟動的 Activity 是當前 Activity(位于返回棧的頂部),則現有實例會接收對 onNewIntent() 的調用,而不是創建Activity 的新實例。 正如前文所述,這**會產生與 "singleTop"launchMode 值相同的行為**。 - **FLAG_ACTIVITY_CLEAR_TOP** 如果正在啟動的 Activity 已在當前任務中運行,則會銷毀當前任務頂部的所有 Activity,并通過 onNewIntent() 將此 Intent 傳遞給 Activity 已恢復的實例(現在位于頂部),而不是啟動該 Activity 的新實例。 產生這種行為的 launchMode 屬性沒有值。 具有此標記為的Activity,當它啟動時,在同一個任務棧中所有位于它上面的Activity 都要出棧。這個模式一般需要和FLAG_ACTIVITY_ NEW_ TASK 配合使用,在這種情況下, 被啟動Activity 的實例如果已經存在,那么系統就會調用它的onNewIntent()。 如果被啟動的Activity 采用standard 模式啟動,那么它連同它之上的Activity 都要出棧,系統會創建新的Activity 實例并放入棧頂。通過1.2.1 節中的分析可以知道, singleTask啟動模式默認就具有此標記位的效果。 FLAG_ACTIVITY_CLEAR_TOP 通常與 FLAG_ACTIVITY_NEW_TASK 結合使用。一起使用時,通過這些標志,可以找到其他任務中的現有 Activity,并將其放入可從中響應 Intent 的位置。 >[info] **注**:如果指定 Activity 的啟動模式為 "standard",則該 Activity 也會從堆棧中移除,并在其位置啟動一個新實例,以便處理傳入的 Intent。 這是因為當啟動模式為 "standard" 時,將始終為新 Intent 創建新實例。 - **FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS** 具**有這個標記的Activity 不會出現在歷史Activity 的列表**中,當某些情況下我們不希望用戶通過歷史列表回到我們的Activity 的時候這個標記比較有用。它等同于在XML 中指定Activity 的屬性`android :excludeFromRecents=true”` ### 處理關聯 **“關聯”指示 Activity 優先屬于哪個任務**。**默認情況下,同一應用中的所有 Activity 彼此關聯**。 因此,**默認情況下,同一應用中的所有 Activity 優先位于相同任務中**。 不過,您**可以修改 Activity 的默認關聯**:在不同應用中定義的 Activity 可以共享關聯,或者可為在同一應用中定義的 Activity 分配不同的任務關聯。 #### 如何關聯 **可以使用 `<activity>` 元素的 [taskAffinity](https://developer.android.com/guide/topics/manifest/activity-element.html#aff) 屬性修改任何給定 Activity 的關聯。** **taskAffinity** 屬性**取字符串值**,該值必**須不同于在 [`<manifest> `](https://developer.android.com/guide/topics/manifest/manifest-element.html)元素中聲明的默認軟件包名稱,因為系統使用該名稱標識應用的默認任務關聯。** 在兩種情況下,關聯會起作用: - 啟動 Activity 的 Intent 包含 [FLAG_ACTIVITY_NEW_TASK](https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_NEW_TASK) 標志。 **默認情況下,新 Activity 會啟動到調用 startActivity() 的 Activity 任務中。它將推入與調用方相同的返回棧**。 **但是,如果傳遞給 [startActivity()](https://developer.android.com/reference/android/app/Activity.html#startActivity(android.content.Intent)) 的 Intent 包含 FLAG_ACTIVITY_NEW_TASK 標志,則系統會尋找其他任務來儲存新 Activity。這通常是新任務,但未做強制要求**。 **如果現有任務與新 Activity 具有相同關聯,則會將 Activity 啟動到該任務中。 否則,將開始新任務。** **如果此標志導致 Activity 開始新任務,且用戶按“主頁”按鈕離開,則必須為用戶提供導航回任務的方式**。 有些實體(如通知管理器)始終在外部任務中啟動 Activity,而從不作為其自身的一部分啟動 Activity,因此它們始終將 FLAG_ACTIVITY_NEW_TASK 放入傳遞給 startActivity() 的 Intent 中。請注意,**如果 Activity 能夠由可以使用此標志的外部實體調用,則用戶可以通過獨立方式返回到啟動的任務**,例如,使用啟動器圖標(任務的根 Activity 具有 [CATEGORY_LAUNCHER](https://developer.android.com/reference/android/content/Intent.html#CATEGORY_LAUNCHER) Intent 過濾器;請參閱下面的[啟動任務](https://developer.android.com/guide/components/tasks-and-back-stack.html#Starting)部分)。 - Activity 將其 allowTaskReparenting 屬性設置為 "true"。 **在這種情況下,Activity 可以從其啟動的任務移動到與其具有關聯的任務(如果該任務出現在前臺)**。 例如,假設將報告所選城市天氣狀況的 Activity(**假定為Activity W**) 定義為**旅行應用(App T**)的一部分。 它(**Activity W**)與同一應用(**App T**)中的其他 Activity 具有相同的關聯(默認應用關聯),并允許利用此屬性重定父級。當您的一個 Activity (**Activity O**)啟動天氣預報 Activity(**Activity W**) 時,它(**Activity W**)最初所屬的任務與您的 Activity (**Activity O**)相同。 但是,當旅行應用(**App T**)的任務出現在前臺時,系統會將天氣預報 Activity (**Activity W**)重新分配給該任務并顯示在其中。 >[info] **提示**:如果從用戶的角度來看,一個 .apk 文件包含多個“應用”,則您可能需要使用 [taskAffinity ](https://developer.android.com/guide/topics/manifest/activity-element.html#aff)屬性將不同關聯分配給與每個“應用”相關的 Activity。 ### 清理返回棧 **如果用戶長時間離開任務,則系統會清除所有 Activity 的任務,根 Activity 除外。 當用戶再次返回到任務時,僅恢復根 Activity。系統這樣做的原因是,經過很長一段時間后,用戶可能已經放棄之前執行的操作,返回到任務是要開始執行新的操作。** 您可以使用下列幾個 Activity 屬性修改此行為: - [alwaysRetainTaskState](https://developer.android.com/guide/topics/manifest/activity-element.html#always) 如果在任務的根 Activity 中將此屬性設置為 "true",則不會發生剛才所述的默認行為。即使在很長一段時間后,任務仍將所有 Activity 保留在其堆棧中。 * [clearTaskOnLaunch](https://developer.android.com/guide/topics/manifest/activity-element.html#clear) **如果在任務的根 Activity 中將此屬性設置為 "true",則每當用戶離開任務然后返回時,系統都會將堆棧清除到只剩下根 Activity。** 換而言之,它與 alwaysRetainTaskState 正好相反。 **即使只離開任務片刻時間,用戶也始終會返回到任務的初始狀態。** * [finishOnTaskLaunch](https://developer.android.com/guide/topics/manifest/activity-element.html#finish) 此屬性類似于 clearTaskOnLaunch,但它**對單個 Activity 起作用,而非整個任務**。 此外,它還**有可能會導致任何 Activity 停止,包括根 Activity。** **設置為 "true" 時,Activity 仍是任務的一部分,但是僅限于當前會話。如果用戶離開然后返回任務,則任務將不復存在。** ### 啟動任務 **通過為 Activity 提供一個以 "`android.intent.action.MAIN`" 為指定操作、以 "`android.intent.category.LAUNCHER`" 為指定類別的 Intent 過濾器,您可以將 Activity 設置為任務的入口點。** 例如: ~~~ <activity ... > <intent-filter ... > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> ... </activity> ~~~ 此類 Intent 過濾器會使 Activity 的圖標和標簽顯示在應用啟動器中,讓用戶能夠啟動 Activity 并在啟動之后隨時返回到創建的任務中。 **第二個功能**非常重要:**用戶必須能夠在離開任務后,再使用此 Activity 啟動器返回該任務**。 因此,**只有在 Activity 具有 [ACTION_MAIN](https://developer.android.com/reference/android/content/Intent.html#ACTION_MAIN) 和 [CATEGORY_LAUNCHER](https://developer.android.com/reference/android/content/Intent.html#CATEGORY_LAUNCHER) 過濾器時,才應該使用將 Activity 標記為“始終啟動任務”的兩種啟動模式,即 "singleTask" 和 "singleInstance"**。例如,我們可以想像一下如果缺少過濾器會發生什么情況: Intent 啟動一個 "singleTask" Activity,從而啟動一個新任務,并且用戶花了些時間處理該任務。然后,用戶按“主頁”按鈕。 任務現已發送到后臺,而且不可見。現在,用戶無法返回到任務,因為該任務未顯示在應用啟動器中。 **如果您并不想用戶能夠返回到 Activity,對于這些情況,請將 `<activity>`元素的 [finishOnTaskLaunch](https://developer.android.com/guide/topics/manifest/activity-element.html#finish) 設置為 "true"(請參閱清理清理返回棧)。** 有關如何在概覽屏幕中顯示和管理任務與 Activity 的更多信息,請參閱[概覽屏幕](https://developer.android.com/guide/components/recents.html)。 ### Android群英傳《摘抄》
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看