Activity的管理有靜態和動態兩層涵義:java
靜態是指Activity的代碼組織結構,即Application中聲明的Activity的集合,這些Activity被組織在一個APK中,有特定的包名。 在編寫應用程序時,Activity對應到用戶界面,它定義了用戶界面的佈局、交互行爲、啓動方式等,最重要的,是Activity的生命週期函數。 在應用進程看來,只須要按照Android定義的規範,實現生命週期函數的具體邏輯便可,全部的用戶界面都遵循同一個規範。 編寫完一個應用程序的全部用戶界面,就算是完成了Activity的靜態管理。android
動態是指Activity的運行調度方式,即Activity生命週期的執行過程當中,內部數據結構的變化,Android對全部Activity進行統一管理。 在一個應用程序安裝時,系統會解析出APK中全部Activity的信息,當顯示APK中的用戶界面時,就須要調度Activity的生命週期函數了。 系統進程(system_process)中維護了全部Activity的狀態,管理中樞就是ActivityManagerService,Android爲此作了精密的設計,採用 棧 做爲基本的數據結構。git
本文分析的Activity管理方式屬於動態這個層面,也就是系統進程中針對Activity的調度機制。github
Activity的管理離不開基礎的數據結構以及它們之間的相互關聯, 因此,筆者會從基礎的數據結構出發,分析類的屬性和行爲,並結合一些場景進行源碼分析; 進一步,會分析各個類之間關聯關係的構建過程。 這樣一來,整個Activity管理運轉的模型就清楚了,這個模型承載的不少業務,本文不會具體展開, 在Android四大組件之Activity–啓動過程一文中,筆者會再詳細介紹一種典型的業務。shell
Activity管理相關的數據結構包括:數組
這些數據結構都是Java類,它們都屬於系統進程的範疇,即對象的構建和銷燬都在系統進程中完成,筆者將從類的屬性和行爲這兩個角度來分析類的職能。 Android有一些約定俗成的函數命名方式,與Activity管理相關不少函數都會帶有Locked後綴,表示這些函數須要進行多線程同步操做(synchronized),它們會讀/寫一些多線程共享的數據,讀者在分析代碼的時候能夠適當關注。瀏覽器
先上一張數據結構的概覽圖:數據結構
圖中的方框能夠理解爲一箇中包含關係:譬如一個TaskRecord中包含多個ActivityRecord; 圖中的鏈接線能夠理解爲等價關係,譬如同一個ActivityRecord會被TaskRecord和ProcessRecord引用,二者是從不一樣維度來管理ActivityRecord。多線程
ActivityRecord是AMS調度Activity的基本單位,它須要記錄AndroidManifest.xml中所定義Activity的靜態特徵,同時, 也須要記錄Activity在被調度時的狀態變化,所以ActivityRecord這個類的屬性比較多。app
屬性 | 描述 |
---|---|
ActivityInfo | 從<activity>標籤中解析出來的信息,包含launchMode,permission,taskAffinity等 |
mActivityType | Activity的類型有三種:APPLICATION_ACTIVITY_TYPE(應用)、HOME_ACTIVITY_TYPE(桌面)、RECENTS_ACTIVITY_TYPE(最近使用) |
appToken | 當前ActivityRecord的標識 |
packageName | 當前所屬的包名,這是由<activity>靜態定義的 |
processName | 當前所屬的進程名,大部分狀況都是由<activity>靜態定義的,但也有例外 |
taskAffinity | 相同taskAffinity的Activity會被分配到同一個任務棧中 |
intent | 啓動當前Activity的Intent |
launchedFromUid | 啓動當前Activity的UID,即發起者的UID |
launchedFromPackage | 啓動當前Activity的包名,即發起者的包名 |
resultTo | 在當前ActivityRecord看來,resultTo表示上一個啓動它的ActivityRecord,當須要啓動另外一個ActivityRecord,會把本身做爲resultTo,傳遞給下一個ActivityRecord |
state | ActivityRecord所處的狀態,初始值是ActivityState.INITIALIZING |
app | ActivityRecord的宿主進程 |
task | ActivityRecord的宿主任務 |
inHistory | 標識當前的ActivityRecord是否已經置入任務棧中 |
frontOfTask | 標識當前的ActivityRecord是否處於任務棧的根部,便是否爲進入任務棧的第一個ActivityRecord |
newIntents | Intent數組,用於暫存尚未調度到應用進程Activity的Intent |
因爲ActivityRecord是一個最基本的數據結構,因此其行爲相對較少,大都是一些用於斷定和更新當前ActivityRecord狀態的函數:
行爲 | 描述 |
---|---|
putInHistory(), takeFromHistory(), isInHistory() | 基於inHistory屬性,來斷定和更新ActivityRecord是否在任務棧的狀態值 |
isHomeActivity(), isRecentsActivity(), isApplicationActivity() | 基於mActivityType屬性,斷定Activity的類型 |
setTask() | 設置ActivityRecord的宿主任務 |
deliverNewIntentLocked() | 向當前ActivityRecord繼續派發Intent。在一些場景下,位於任務棧頂的ActivityRecord會繼續接受新的Intent(譬如以singleTop方式啓動的同一個Activity),這時候,會觸發調度Activity.onNewIntent()函數 |
addNewIntentLocked() | 若是Intent沒有派發到應用進程,則經過該函數往newIntents數組中添加一個元素。 |
要理解ActivityRecord這個數據結構,能夠從其構造函數出發,理解其屬性在什麼場景下會發生變化。 每次須要啓動一個新的Activity時,都會構建一個ActivityRecord對象,這在ActivityStackSupervisor.startActivityLocked()函數中完成,構造一個ActivityRecord要傳入的參數是至關多的:
ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType, ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo, String _resultWho, int _reqCode, boolean _componentSpecified, ActivityStackSupervisor supervisor, ActivityContainer container, Bundle options) { service = _service; // AMS對象 appToken = new Token(this); //appToken能夠進行跨進程傳遞,標識一個AR對象 info = aInfo; //從AndroidManifest.xml中解析獲得的Activity信息 launchedFromUid = _launchedFromUid; //譬如從瀏覽器啓動當前AR,那麼該屬性記錄的就是瀏覽器的UID launchedFromPackage = _launchedFromPackage; userId = UserHandle.getUserId(aInfo.applicationInfo.uid); intent = _intent; //啓動當前AR的Intent shortComponentName = _intent.getComponent().flattenToShortString(); resolvedType = _resolvedType; componentSpecified = _componentSpecified; configuration = _configuration; resultTo = _resultTo; //記錄上一個AR對象 resultWho = _resultWho; //reslutTo的字符串標識 requestCode = _reqCode; //上一個AR對象設定的Request Code state = ActivityState.INITIALIZING; //AR的狀態,Activity調度時發生改變 frontOfTask = false; //是否處於Task的根部,調整任務棧中AR順序時,可能發生改變 launchFailed = false; stopped = false; //pause操做完成狀態位 delayedResume = false; finishing = false; //stoped到finished之間的過渡狀態位 configDestroy = false; keysPaused = false; //若是置爲true,則當前AR再也不接受用戶輸入 inHistory = false; //將AR壓入任務棧後,該狀態位被置爲true visible = true; waitingVisible = false; nowVisible = false; idle = false; hasBeenLaunched = false; mStackSupervisor = supervisor; mInitialActivityContainer = container; if (options != null) { pendingOptions = new ActivityOptions(options); mLaunchTaskBehind = pendingOptions.getLaunchTaskBehind(); } haveState = true; if (aInfo != null) { //根據aInfo給realActivity, taskAffinity, processName等屬性賦值 ... } else { //沒有aInfo的狀況下,賦予默認值 realActivity = null; taskAffinity = null; stateNotNeeded = false;