摘要:如果具有默認的啟動模式,則會啟動該類的新實例,且堆棧會變成。但是,如果的啟動模式是,則的現有實例會通過接收,因為它位于堆棧的頂部而堆棧仍為。上圖顯示如何將啟動模式為的添加到返回棧。任務的親和關系由其根的親和關系確定。
Android 啟動模式--任務(Task)--桟 的誤區
概念寫這篇文章是因為前幾天的一次面試,面試官說SingleInstance模式會新建一個桟,而SingleTask不會.首先不說這個對不對(非要說對錯的話,那就是錯.),因為這句話是含糊不清的.桟?只的是返回桟? 還是任務桟?有沒有考慮taskAffinity屬性?所以籠統的那樣說是不對的.這篇文章一是為了記錄,二是為了說清楚----任務(Task)& 桟(返回桟,任務桟).
桟(堆棧:stack)
棧的基本特點:
先入后出,后入先出。
除頭尾節點之外,每個元素有一個前驅,一個后繼。
任務
任務是指在執行特定作業時與用戶交互的一系列 Activity。 這些 Activity 按照各自的打開順序排列在堆棧(即返回棧)中。
返回桟
在官方文檔中,找不到關于返回桟的概念,但是按照官方文檔在描述時的語境,可以理解為響應Android返回鍵的順序隊列.這是站在用戶的直觀感受上的描述.Android 內部的描述單位只有任務(Task).
任務桟
在官方文檔中沒有這個概念.我為了方便理解,把任務中按照桟規則的順序隊列的 一系列 Activity 稱為 任務棧.
由于 官方文檔中沒有詳細的說明什么是返回桟,在實際的開發中如果以棧為基本度量單位的話,很容易被自己繞暈,如果按照任務為基本度量單位的話就很容易理清楚 Android 四大啟動模式了.我個人把返回棧理解為這樣子的: 返回桟僅有一個(因為返回鍵只有一個),返回桟操作的基本元素是任務,返回鍵操作的是返回桟中處于前臺的任務,每個任務維護著一系列 Activity 組成的棧以響應返回鍵.
Activity 四大啟動模式"standard"(默認模式)
默認。系統在啟動 Activity 的任務中創建 Activity 的新實例并向其傳送 Intent。Activity 可以多次實例化,而每個實例均可屬于不同的任務,并且一個任務可以擁有多個實例。
"singleTop"
如果當前任務的頂部已存在 Activity 的一個實例,則系統會通過調用該實例的 onNewIntent() 方法向其傳送 Intent,而不是創建 Activity 的新實例。Activity 可以多次實例化,而每個實例均可屬于不同的任務,并且一個任務可以擁有多個實例(但前提是位于返回棧頂部的 Activity 并不是 Activity 的現有實例)。
例如,假設任務的返回棧包含根 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() 接收 Intent,因為它位于堆棧的頂部;而堆棧仍為 A-B-C-D。但是,如果收到針對 B 類 Activity 的 Intent,則會向堆棧添加 B 的新實例,即便其啟動模式為 "singleTop" 也是如此。
注:為某個 Activity 創建新實例時,用戶可以按“返回”按鈕返回到前一個 Activity。 但是,當 Activity 的現有實例處理新 Intent 時,則在新 Intent 到達 onNewIntent() 之前,用戶無法按“返回”按鈕返回到 Activity 的狀態。
"singleTask"
系統創建新任務并實例化位于新任務底部的 Activity。但是,如果該 Activity 的一個實例已存在于一個多帶帶的任務中,則系統會通過調用現有實例的 onNewIntent() 方法向其傳送 Intent,而不是創建新實例。一次只能存在 Activity 的一個實例。
注:盡管 Activity 在新任務中啟動,但是用戶按“返回”按鈕仍會返回到前一個 Activity。
"singleInstance".
與 "singleTask" 相同,只是系統不會將任何其他 Activity 啟動到包含實例的任務中。該 Activity 始終是其任務唯一僅有的成員;由此 Activity 啟動的任何 Activity 均在多帶帶的任務中打開。
我們再來看另一示例,Android 瀏覽器應用聲明網絡瀏覽器 Activity 應始終在其自己的任務中打開(通過在
無論 Activity 是在新任務中啟動,還是在與啟動 Activity 相同的任務中啟動,用戶按“返回”按鈕始終會轉到前一個 Activity。 但是,如果啟動指定 singleTask 啟動模式的 Activity,則當某后臺任務中存在該 Activity 的實例時,整個任務都會轉移到前臺。此時,返回棧包括上移到堆棧頂部的任務中的所有 Activity。 上圖顯示了這種情況。
上圖 顯示如何將啟動模式為“singleTask”的 Activity 添加到返回棧。 如果 Activity 已經是某個擁有自己的返回棧的后臺任務的一部分,則整個返回棧也會上移到當前任務的頂部。
關于android:taskAffinity屬性參考:2017-03-14日摘自官方文檔(后期可能有變更以官網為準)
android:taskAffinity
與 Activity 有著親和關系的任務。從概念上講,具有相同親和關系的 Activity 歸屬同一任務(從用戶的角度來看,則是歸屬同一“應用”)。 任務的親和關系由其根 Activity 的親和關系確定。
親和關系確定兩件事 - Activity 更改到的父項任務(請參閱 allowTaskReparenting 屬性)和通過 FLAG_ACTIVITY_NEW_TASK 標志啟動 Activity 時將用來容納它的任務。
默認情況下,應用中的所有 Activity 都具有相同的親和關系。您可以設置該屬性來以不同方式組合它們,甚至可以將在不同應用中定義的 Activity 置于同一任務內。 要指定 Activity 與任何任務均無親和關系,請將其設置為空字符串。
如果未設置該屬性,則 Activity 繼承為應用設置的親和關系(請參閱
測試 SingleTask與SingleInstance的異同參考:2017-03-14日摘自官方文檔(后期可能有變更以官網為準)
我寫了一個Demo測試了下:
當我把SingleTaskA配置為:
在SingleTaskA中啟動一個標準模式的StandardBActivity:
public class SingleTaskA extends BaseLauncherModeActivity { @Override protected Class gotoActivity() { return StandardB.class; } @Override protected String setModeTextShow() { return Constant.SINGLE_TASK; } }
而在StandardB中,我一直啟動StandardB自己:
public class StandardB extends BaseLauncherModeActivity { @Override protected Class gotoActivity() { return StandardB.class; } @Override protected String setModeTextShow() { return Constant.STANDARD+"Repeat"; } }
補充下基類:
public abstract class BaseLauncherModeActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_base_launcher_mode); String text = setModeTextShow(); Button button = (Button) findViewById(R.id.bt); button.setText("模式: "+text); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Class aClass = gotoActivity(); if (aClass==null)return; startActivity(new Intent(getApplicationContext(),aClass)); } }); int taskId = getTaskId(); Log.d(Constant.TAG,"taskId: "+taskId); } protected abstract Class gotoActivity(); protected abstract String setModeTextShow(); }
得到如下結果:
03-14 10:32:32.287 22561-22561/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 26 03-14 10:32:37.691 22561-22561/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 26 03-14 10:32:42.120 22561-22561/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 27 03-14 10:32:45.961 22561-22561/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 27 03-14 10:32:52.105 22561-22561/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 27 03-14 10:32:53.531 22561-22561/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 27 03-14 10:32:55.748 22561-22561/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 27 03-14 10:32:56.763 22561-22561/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 27
可以看到,SingleTaskA啟動了一個新的任務(Task),id為27,之后在SingleTaskA中啟動StandardB并沒有做其他的操作,而是直接在剛剛SingleTaskA啟動的任務中添加.
現在我去掉 taskAffinity屬性的定義,得到:
03-14 16:42:10.604 31062-31062/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 29 03-14 16:42:15.261 31062-31062/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 29 03-14 16:42:16.865 31062-31062/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 29 03-14 16:42:19.197 31062-31062/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 29 03-14 16:42:20.232 31062-31062/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 29 03-14 16:42:21.049 31062-31062/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 29 03-14 16:42:22.180 31062-31062/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 29
可見,默認是不會創建新的任務的.
現在,把SingleTaskA 改為 SingleInstanceA,然后在其中可以啟動StandardB(上面有代碼),得到如下結果:
03-14 16:46:59.669 2273-2273/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 30 03-14 16:47:09.367 2273-2273/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 30 03-14 16:47:10.602 2273-2273/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 31 03-14 16:47:12.013 2273-2273/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 30 03-14 16:47:14.438 2273-2273/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 30 03-14 16:47:15.429 2273-2273/com.didikee.androidlaunchermode D/AndroidLauncherMode: taskId: 30
可見,SingleInstanceA新建了一個任務id為31,在 SingleInstanceA 中啟動 StandardB 還是繼續添加在之前任務中.
總結:Android 是以任務為核心的,不要被棧帶偏了.
SingleInstance 一定會新建一個任務,并且該任務中僅包含一個實例.
SingleTask默認不會創建新任務,但是可以通過taskAffinity達到創建新任務的目的,創建的任務可添加其他元素.
最后,說的不對的歡迎交流.
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66814.html
閱讀 1025·2022-07-19 10:19
閱讀 1800·2021-09-02 15:15
閱讀 1013·2019-08-30 15:53
閱讀 2659·2019-08-30 13:45
閱讀 2658·2019-08-26 13:57
閱讀 1988·2019-08-26 12:13
閱讀 1010·2019-08-26 10:55
閱讀 551·2019-08-26 10:46