ActivityStack
ActivityStack 是一個管理類粮呢,用來管理系統(tǒng)所有 Activity 的各種狀態(tài)茧彤,其內(nèi)部維護了 TaskRecord 的列表屎勘,因此從 Activity 任務棧這一角度來說示启,ActivityStack 也可以理解為 Activity 堆棧湃密。
它由 ActivityStackSupervisor 來進行管理的巫员,而 ActivityStackSupervisor 在 AMS 中的構造方法中被創(chuàng)建庶香。
ActivityStack 的實例類型
<pre class="md-fences md-end-block" lang="java" contenteditable="false" cid="n9" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9rem; white-space: pre; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; padding-left: 1ch; padding-right: 1ch; margin-left: 2em; width: inherit; color: rgb(31, 9, 9); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;">//com.android.server.am.ActivityStackSupervisor
public final class ActivityStackSupervisor implements DisplayListener {
...
ActivityStack mHomeStack;//存儲 Launcher App 的所有 Activity
ActivityStack mFocusedStack;//當前正在接收輸入或啟動下一個 Activity 的所有 Activity
private ActivityStack mLastFocusedStack;//此前接收過輸入的所有 Activity
...
}</pre>
ActivityRecord
ActivityRecord 用來記錄一個 Activity 的所有信息。從 Activity 任務棧的角度來說简识,一個或多個 ActivityRecord 會組成一個 TaskRecord赶掖,TaskRecord 用來記錄 Activity 的棧,而 ActivityStack 包含了一個或多個 TaskRecord七扰。
<pre class="md-fences md-end-block" lang="java" contenteditable="false" cid="n13" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9rem; white-space: pre; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; padding-left: 1ch; padding-right: 1ch; margin-left: 2em; width: inherit; color: rgb(31, 9, 9); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;">
//在 ActivityStack 中定義了一些特殊狀態(tài)的 Activity
ActivityRecord mPausingActivity = null;//正在暫停的Activity
ActivityRecord mLastPausedActivity = null;//上一個已經(jīng)暫停的Activity
ActivityRecord mLastNoHistoryActivity = null;//最近一次沒有歷史記錄的Activity
ActivityRecord mResumedActivity = null;//已經(jīng)Resume的Activity
ActivityRecord mLastStartedActivity = null;//最近一次啟動的Activity
ActivityRecord mTranslucentActivityWaiting = null;//傳遞給convertToTranslucent方法的最上層的Activity</pre>
ActivityState
<pre class="md-fences md-end-block" lang="java" contenteditable="false" cid="n15" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9rem; white-space: pre; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; padding-left: 1ch; padding-right: 1ch; margin-left: 2em; width: inherit; color: rgb(31, 9, 9); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;">
//通過枚舉存儲了 Activity 的所有的9種狀態(tài)
enum ActivityState {
INITIALIZING,
RESUMED,
PAUSING,
PAUSED,
STOPPING,
STOPPED,
FINISHING,
DESTROYING,
DESTROYED
}</pre>
維護的 ArrayList
ActivityStack 中維護了很多 ArrayList奢赂,這些 ArrayList 中的元素類型主要有 ActivityRecord 和 TaskRecord,其中 TaskRecord 用來記錄 Activity 的 Task颈走。
ARRAYLIST | 元素類型 | 說明 |
---|---|---|
mTaskHistory | TaskRecord | 所有沒有被銷毀的 Task |
mLRUActivities | ActivityRecord | 正在運行的 Activity膳灶,列表中的第一個條目是最近最少使用的元素 |
mNoAnimActivities | ActivityRecord | 不考慮轉(zhuǎn)換動畫的 Activity |
mValidateAppTokens | TaskGroup | 用于與窗口管理器驗證應用令牌 |
Activity 棧管理
Activity 是由任務棧來進行管理的,有了棧管理立由,我們可以對應用程序進行操作轧钓,應用可以復用自身應用中以及其他應用的 Activity,節(jié)省了資源锐膜。
比如我們使用一款社交應用毕箍,這個應用的聯(lián)系人詳情界面提供了聯(lián)系人的郵箱,當我們點擊郵箱時會跳到發(fā)送郵件的界面道盏。社交應用和系統(tǒng) Email 中的 Activity 是處于不同應用程序進程的而柑,而有了棧管理,就可以把發(fā)送郵件界面放到社交應用中詳情界面所在棧的棧頂荷逞,來做到跨進程操作媒咳。
Launch Mode
Launch Mode用于設定 Activity 的啟動方式,無論是哪種啟動方式种远,所啟動的 Activity 都會位于 Activity 棧的棧頂涩澡。有以下四種:
standerd:默認模式,每次啟動 Activity 都會創(chuàng)建一個新的 Activity 實例院促。
singleTop:如果要啟動的 Activity 已經(jīng)在棧頂筏养,則不會重新創(chuàng)建 Activity,同時該 Activity 的 onNewIntent 方法會被調(diào)用常拓。如果要啟動的 Activity 不在棧頂渐溶,則會重新創(chuàng)建該 Activity 的實例。
singleTask:如果要啟動的 Activity 已經(jīng)存在于它想要歸屬的棧中弄抬,那么不會創(chuàng)建該 Activity 實例茎辐,將棧中位于該 Activity 上的所有的 Activity 出棧浅缸,同時該 Activity 的 onNewIntent 方法會被調(diào)用。如果要啟動的 Activity 不存在于它想要歸屬的棧中庇绽,并且該棧存在教届,則會創(chuàng)建該 Activity 的新實例。如果要啟動的 Activity 想要歸屬的棧不存在依啰,則首先要創(chuàng)建一個新棧乎串,然后創(chuàng)建該 Activity 實例并壓入到新棧中。
singleInstance:啟動 Activity 時速警,首先要創(chuàng)建在一個新棧叹誉,然后創(chuàng)建該 Activity 實例并壓入新棧中,新棧中只會存在這一個 Activity 實例闷旧。
Intent 的 FLAG
Intent 中定義了很多了 FLAG长豁,其中有幾個 FLAG 也可以設定 Activity 的啟動方式,如果 Launch Mode 設定和 FLAG 設定的 Activity 的啟動方式有沖突忙灼,則以 FLAG 設定的為準匠襟。
FLAG_ACTIVITY_SINGLE_TOP:和 Launch Mode 中的 singleTop 效果是一樣的。
FLAG_ACTIVITY_NEW_TASK:和 Launch Mode 中的 singleTask 效果是一樣的该园。這個名字比較奇怪要注意了酸舍。
FLAG_ACTIVITY_CLEAR_TOP:Launch Mode 中沒有與此對應的模式,如果要啟動的 Activity 已經(jīng)存在于棧中爬范,則將所有位于它上面的 Activity 出棧父腕。singleTask 默認具有此標記位的效果。
除了這三個 FLAG青瀑,還有一些 FLAG 對我們分析棧管理有些幫助璧亮。
FLAG_ACTIVITY_NO_HISTORY:Activity 一旦退出,就不會存在于棧中斥难。同樣的枝嘶,也可以在 AndroidManifest.xml 中設置 “android:noHistory”。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:Activity 不會被放入到 “最近啟動的 Activity” 列表中哑诊。
FLAG_ACTIVITY_BROUGHT_TO_FRONT:這個標志位通常不是由應用程序中的代碼設置的群扶,而是 Launch Mode 為 singleTask 時,由系統(tǒng)自動加上的镀裤。
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY:這個標志位通常不是由應用程序中的代碼設置的竞阐,而是從歷史記錄中啟動的(長按 Home 鍵調(diào)出)。
FLAG_ACTIVITY_MULTIPLE_TASK:需要和 FLAG_ACTIVITY_NEW_TASK 一同使用才有效果暑劝,系統(tǒng)會啟動一個新的棧來容納新啟動的 Activity.
FLAG_ACTIVITY_CLEAR_TASK:需要和 FLAG_ACTIVITY_NEW_TASK 一同使用才有效果骆莹,用于清除與啟動的 Activity 相關棧的所有其他 Activity。
計算Flag
根 Activity 啟動時會調(diào)用 AMS 的 startActivity 方法担猛,經(jīng)過層層調(diào)用會調(diào)用 ActivityStarter 的 startActivityUnchecked 方法
<pre class="md-fences md-end-block" lang="java" contenteditable="false" cid="n100" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9rem; white-space: pre; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; padding-left: 1ch; padding-right: 1ch; margin-left: 2em; width: inherit; color: rgb(31, 9, 9); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;">
//com.android.server.am.ActivityStarter#startActivityUnchecked
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);//重置各種配置再進行配置幕垦,如:ActivityRecord丢氢、Intent、TaskRecord 和 LaunchFlags(啟動的 FLAG)等
computeLaunchingTaskFlags();//計算出啟動的 FLAG先改,并將計算的值賦值給 mLaunchFlags
computeSourceStack();
mIntent.setFlags(mLaunchFlags);//將 mLaunchFlags 設置給 Intent疚察,達到設定 Activity 的啟動方式的目的
...
}
//com.android.server.am.ActivityStarter#computeLaunchingTaskFlags
private void computeLaunchingTaskFlags() {
...
if (mInTask == null) {// TaskRecord 類型的 mInTask 為 null 時,說明 Activity 要加入的棧不存在
if (mSourceRecord == null) {//初始 Activity(ActivityA 啟動了 ActivityB仇奶,ActivityA 就是初始 Activity)為null
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {//需要創(chuàng)建一個新棧
Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
"Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
} else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {//如果 "初始 Activity" 所在的棧只允許有一個 Activity 實例貌嫡,則需要創(chuàng)建一個新棧
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
} else if (mLaunchSingleInstance || mLaunchSingleTask) {//Launch Mode 設置了 singleTask 或 singleInstance,則也要創(chuàng)建一個新棧
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
}
}</pre>
taskAffinity
任務的親近性猜嘱,可以在 AndroidManifest.xml 設置 android:taskAffinity衅枫,用來指定 Activity 希望歸屬的棧嫁艇, 默認情況下朗伶,同一個應用程序的所有的 Activity 都有著相同的 taskAffinity。
taskAffinity 在下面兩種情況時會產(chǎn)生效果步咪。
taskAffinity 與 FLAG_ACTIVITY_NEW_TASK 或者 singleTask 配合论皆。如果新啟動 Activity 的 taskAffinity 和棧的 taskAffinity 相同(棧的 taskAffinity 取決于根 Activity 的 taskAffinity)則加入到該棧中。如果不同猾漫,就會創(chuàng)建新棧点晴。
taskAffinity 與 allowTaskReparenting 配合。如果 allowTaskReparenting 為 true悯周,說明 Activity 具有轉(zhuǎn)移的能力粒督。拿此前的郵件為例,當社交應用啟動了發(fā)送郵件的 Activity禽翼,此時發(fā)送郵件的 Activity 是和社交應用處于同一個棧中屠橄。如果發(fā)送郵件的 Activity 的 allowTaskReparenting 設置為 true,此后郵件程序所在的棧位于前臺闰挡,這個時候發(fā)送郵件的 Activity 就會由社交應用的棧中轉(zhuǎn)移到與它更親近的郵件程序(taskAffinity 相同)所在的棧中锐墙。
taskAffinity的計算
<pre class="md-fences md-end-block" lang="java" contenteditable="false" cid="n114" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9rem; white-space: pre; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; padding-left: 1ch; padding-right: 1ch; margin-left: 2em; width: inherit; color: rgb(31, 9, 9); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;">
//com.android.server.am.ActivityStack#findTaskLocked
void findTaskLocked(ActivityRecord target, FindTaskResult result) {
...
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {//遍歷 mTaskHistory 列表,列表的元素為 TaskRecord长酗,
用于存儲沒有被銷毀的 Task
final TaskRecord task = mTaskHistory.get(taskNdx);//得到某一個 Task 的信息
...
else if (!isDocument && !taskIsDocument
&& result.r == null && task.canMatchRootAffinity()) {
if (task.rootAffinity.equals(target.taskAffinity)) {//將 Task 的 rootAffinity(初始的 taskAffinity)和目標 Activity 的 taskAffinity 做對比溪北,如果相同,則將 FindTaskResult 的 matchedByRootAffinity 屬性設置為 true夺脾,說明找到了匹配的 Task
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
result.r = r;
result.matchedByRootAffinity = true;
}
} else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
}
}</pre>