<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在Android 10 App啟動分析之Activity啟動篇(二)一文中,簡單地介紹了Activity的生命週期管理器是如何排程Activity進入onCreate生命週期的流程。這篇文章,我們將詳細地分析framework中activity的生命週期管理功能,從更宏觀的角度來更全面地瞭解生命週期及相關事務的工作原理。
生命週期管理是google在Android 9才引入的設計,在Android 9之前,activity 存在生命週期的概念,但並無生命週期管理這一說法。為了方便生命週期的切換以及相關業務的管理,google採用了事務的思想,將生命週期抽象為使用者端事務的一部分來統一管理。下圖是使用者端事務管理完整的UML圖:
相關類說明:
preExecute
、execute
、postExecute
三個介面,分別代表事務執行前、執行中、執行後三個階段的回撥方法。DestroyActivityItem
、PauseActivityItem
、StopActivityItem
、ResumeActivityItem
,表示具體的activity生命週期轉換事務。ActivityLifecycleItem
是它的子類之一。除此之外,還有如下內建的使用者端事務:Transaction Name | Desc |
---|---|
ConfigurationChangeItem | App configuration 改變的訊息 |
WindowVisibilityItem | Window可見性發生改變的訊息 |
MoveToDisplayItem | Activity 移動到不同的顯示裝置的訊息 |
MultiWindowModeChangeItem | 多視窗模式改變的訊息 |
ActivityConfigurationChangeItem | Activity configuration 改變的回撥 |
PipModeChangeItem | 畫中畫模式改變的訊息 |
ActivityResultItem | Activity result的回撥 |
NewIntentItem | New intent訊息 |
TopResumedActivityChangeItem | Top resumed activity 改變的回撥 |
ActivityRelaunchItem | 重啟Activity的回撥 |
LaunchActivityItem | 請求啟動一個Activity |
ClientLifecycleManager
在ActivityTaskManagerService
中初始化了唯一的範例,所有的事務操作,必須通過ATMS中的範例來發起。如: mService.getLifecycleManager().scheduleTransaction(clientTransaction);
。
ClientLifecycleManager
的原始碼如下:
class ClientLifecycleManager { void scheduleTransaction(ClientTransaction transaction) throws RemoteException { final IApplicationThread client = transaction.getClient(); transaction.schedule(); if (!(client instanceof Binder)) { // If client is not an instance of Binder - it's a remote call and at this point it is // safe to recycle the object. All objects used for local calls will be recycled after // the transaction is executed on client in ActivityThread. transaction.recycle(); } } void scheduleTransaction(@NonNull IApplicationThread client, @NonNull IBinder activityToken, @NonNull ActivityLifecycleItem stateRequest) throws RemoteException { final ClientTransaction clientTransaction = transactionWithState(client, activityToken, stateRequest); scheduleTransaction(clientTransaction); } void scheduleTransaction(@NonNull IApplicationThread client, @NonNull IBinder activityToken, @NonNull ClientTransactionItem callback) throws RemoteException { final ClientTransaction clientTransaction = transactionWithCallback(client, activityToken, callback); scheduleTransaction(clientTransaction); } void scheduleTransaction(@NonNull IApplicationThread client, @NonNull ClientTransactionItem callback) throws RemoteException { final ClientTransaction clientTransaction = transactionWithCallback(client, null /* activityToken */, callback); scheduleTransaction(clientTransaction); } private static ClientTransaction transactionWithState(@NonNull IApplicationThread client, @NonNull IBinder activityToken, @NonNull ActivityLifecycleItem stateRequest) { final ClientTransaction clientTransaction = ClientTransaction.obtain(client, activityToken); clientTransaction.setLifecycleStateRequest(stateRequest); return clientTransaction; } private static ClientTransaction transactionWithCallback(@NonNull IApplicationThread client, IBinder activityToken, @NonNull ClientTransactionItem callback) { final ClientTransaction clientTransaction = ClientTransaction.obtain(client, activityToken); clientTransaction.addCallback(callback); return clientTransaction; } }
可以看到,ClientLifecycleManager
對外暴露了三種事務排程方法:一是 直接排程一個事務集(ClientTransaction);二是排程一個 Lifecycle事務; 三是呼叫一個Callback事務(ps:除LifeCycle以外的事務,都屬於Callback事務)。實際上,無論是Lifecycle事務還是Callback事務,它們都被封裝成了事務集的形式,並通過ClientTransaction
中的schedule
方法去進一步處理。
ClientTransaction
裡的schedule
方法非常簡單,程式碼如下所示:
public void schedule() throws RemoteException { mClient.scheduleTransaction(this); }
上述程式碼片段中的mClient
到底指的是什麼?
從原始碼的角度來看,mClient 是 ApplicationThread的一個範例。而 ApplicationThread 是ActivityThread的一個內部類,作為ActivityThread 與外部溝通的橋樑。所有的事務集最終都會被派發到ActivityThread中統一處理。
ActivityThread.java void scheduleTransaction(ClientTransaction transaction) { transaction.preExecute(this); sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); }
ActivityThread裡首先呼叫了ClientTransaction
中的preExecute
方法,程式碼片段如下:
public void preExecute(android.app.ClientTransactionHandler clientTransactionHandler) { if (mActivityCallbacks != null) { final int size = mActivityCallbacks.size(); for (int i = 0; i < size; ++i) { mActivityCallbacks.get(i).preExecute(clientTransactionHandler, mActivityToken); } } if (mLifecycleStateRequest != null) { mLifecycleStateRequest.preExecute(clientTransactionHandler, mActivityToken); } }
可以看到,ClientTransaction
先呼叫了 所有註冊的Callback事務的preExecute方法,然後呼叫了唯一的LifeCycle事務的preExecute方法。
在完成所有事務的preExecute邏輯後,ActivityThread
傳送了一條ActivityThread.H.EXECUTE_TRANSACTION
的message,內容如下:
mTransactionExecutor.execute(transaction); if (isSystem()) { transaction.recycle(); }
接下來由TransactionExecutor
負責後續的邏輯處理。
public void execute(ClientTransaction transaction) { final IBinder token = transaction.getActivityToken(); if (token != null) { final Map<IBinder, ClientTransactionItem> activitiesToBeDestroyed = mTransactionHandler.getActivitiesToBeDestroyed(); final ClientTransactionItem destroyItem = activitiesToBeDestroyed.get(token); if (destroyItem != null) { if (transaction.getLifecycleStateRequest() == destroyItem) { // It is going to execute the transaction that will destroy activity with the // token, so the corresponding to-be-destroyed record can be removed. activitiesToBeDestroyed.remove(token); } if (mTransactionHandler.getActivityClient(token) == null) { // The activity has not been created but has been requested to destroy, so all // transactions for the token are just like being cancelled. Slog.w(TAG, tId(transaction) + "Skip pre-destroyed transaction:n" + transactionToString(transaction, mTransactionHandler)); return; } } } executeCallbacks(transaction); executeLifecycleState(transaction); mPendingActions.clear(); }
execute
中有一段對DestroyActivityItem
特殊處理的邏輯,不太重要,我們忽略它。
我們分別來看一下executeCallbacks
和executeLifecycleState
兩個方法。
public void executeCallbacks(ClientTransaction transaction) { final List<ClientTransactionItem> callbacks = transaction.getCallbacks(); if (callbacks == null || callbacks.isEmpty()) { return; } final IBinder token = transaction.getActivityToken(); ActivityClientRecord r = mTransactionHandler.getActivityClient(token); // In case when post-execution state of the last callback matches the final state requested // for the activity in this transaction, we won't do the last transition here and do it when // moving to final state instead (because it may contain additional parameters from server). final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest(); final int finalState = finalStateRequest != null ? finalStateRequest.getTargetState() : UNDEFINED; // Index of the last callback that requests some post-execution state. final int lastCallbackRequestingState = lastCallbackRequestingState(transaction); final int size = callbacks.size(); for (int i = 0; i < size; ++i) { final ClientTransactionItem item = callbacks.get(i); if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item); final int postExecutionState = item.getPostExecutionState(); final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r, item.getPostExecutionState()); if (closestPreExecutionState != UNDEFINED) { cycleToPath(r, closestPreExecutionState, transaction); } item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); if (r == null) { // Launch activity request will create an activity record. r = mTransactionHandler.getActivityClient(token); } if (postExecutionState != UNDEFINED && r != null) { // Skip the very last transition and perform it by explicit state request instead. final boolean shouldExcludeLastTransition = i == lastCallbackRequestingState && finalState == postExecutionState; cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction); } } }
上述程式碼主要做了以下幾件事:
google這段邏輯寫的極為繁雜囉嗦,讓人吐槽的點實在太多了,但還是要在此講一下它是怎麼設計的,原始碼中又哪裡糟點。
首先是事務集的target lifecycle,它指的是事務集中唯一的Lifecycle事務(如果存在的話)的狀態,表示事務集執行完畢後,Activity最終的生命週期狀態。
第二點,事務集中最後一次Activity生命週期轉換的Callback索引,這句話是什麼含義呢?
Callback事務中有這麼一個方法,getPostExecutionState
,它表示在當前Callback事務執行完畢後Activity所需處於的生命週期狀態,為方便敘述,下文稱其為結束狀態。將Callback事務列表從後向前遍歷,如果當前事務存在結束狀態(即getPostExecutionState的值不為UNDEFINED),且與上一個結束狀態相同,記錄下此時事務在列表中的索引值,直到當前結束狀態與上一個狀態不同為止。此時,上一個事務的索引值即為事務集中最後一次Activity生命週期轉換的Callback索引。
假如某事務集有這樣一組Callback事務——ConfigurationChangeItem、NewIntentItem、ConfigurationChangeItem、NewIntentItem。其中ConfigurationChangeItem
的結束狀態為UNDEFINED,NewIntentItem
的結束狀態為ON_RESUME。
我們從後向前開始遍歷:
因此,此事務集中最後一次Activity生命週期轉換的Callback索引 為1。至於這個索引值有什麼意義呢,待會再解釋。
然而,這段設計中還是有幾點需要吐槽一下:
public class ActivityResultItem extends ClientTransactionItem { @UnsupportedAppUsage private List<ResultInfo> mResultInfoList; /* TODO(b/78294732) @Override public int getPostExecutionState() { return ON_RESUME; }*/ }
Excuse me? TODO state!! 實際上,這個TODO 一直拖到android 13 才被加上,en~~~~。
第四點,如果Callback事務的結束狀態為ON_RESUME,則判斷當前Activity狀態是更靠近ON_START狀態還是ON_PAUSE狀態,並將activity狀態轉換到就近狀態(ON_START or ON_PAUSE)。
這裡判斷當前Activity狀態更靠近ON_START還是ON_PAUSE,採用的是路徑長度比較法。framework中為Activity定義了九種狀態,具體如下:
public static final int UNDEFINED = -1; public static final int PRE_ON_CREATE = 0; public static final int ON_CREATE = 1; public static final int ON_START = 2; public static final int ON_RESUME = 3; public static final int ON_PAUSE = 4; public static final int ON_STOP = 5; public static final int ON_DESTROY = 6;
狀態之間的轉換路徑如下表所示:
上表中置灰的單元格,表示不存在或禁止的狀態轉換,而單元格中A ~ B 這種寫法 表示 從 A到 B狀態之間的中間所有狀態,如: start 狀態為 PRE_CREATE , finish 狀態為 DESTROY ,在上表中狀態轉換路徑為 create ~ destroy,表示 activity從 PRE_CREATE 狀態轉換到 DESTROY 狀態,需要經歷 create、start 、 resume 、pause 、stop 、 detroy ,即create到destroy之間所有的生命週期變換的過程。同時,我們也稱 create~destroy 是 PRE_CREATE到DESTROY狀態路徑,它的路徑長度為6。
如何判斷當前生命週期是更靠近ON_START還是ON_PAUSE?我們舉個例子來看一下,假如當前的生命週期為ON_STOP,由上述狀態路徑表可知,從ON_STOP狀態轉換到ON_START狀態的路徑為restart、start,長度為2;而由ON_STOP狀態轉換到ON_PAUSE狀態的路徑為restart、start~pause,長度為4。因此,當前activity的狀態更靠近ON_START。
在路徑長度演演算法的程式碼裡,google給凡是路徑中含有destroy狀態的長度,賦予了一段懲罰長度,讓它的長度增加了10,具體程式碼如下:
public int getClosestOfStates(ActivityClientRecord r, int[] finalStates) { if (finalStates == null || finalStates.length == 0) { return UNDEFINED; } final int currentState = r.getLifecycleState(); int closestState = UNDEFINED; for (int i = 0, shortestPath = Integer.MAX_VALUE, pathLength; i < finalStates.length; i++) { getLifecyclePath(currentState, finalStates[i], false /* excludeLastState */); pathLength = mLifecycleSequence.size(); if (pathInvolvesDestruction(mLifecycleSequence)) { //路徑中含有destroy狀態,增加懲罰長度 pathLength += DESTRUCTION_PENALTY; } if (shortestPath > pathLength) { shortestPath = pathLength; closestState = finalStates[i]; } } return closestState; }
然而我們可以看一下表格中finish state為 START 和 PAUSE的兩列,所有的路徑中都不包含 destroy 狀態,所以這個懲罰長度的意義何在?
第五步開始,正式執行 事務的execute和postExecute邏輯。這裡要談一下,為什麼執行結束狀態為 ON_RESUME的事務時,先要在第四步將 狀態切換到 ON_START 或 ON_RESUME後,然後才開始去執行事務的邏輯呢?
在Android 10中,結束狀態為 ON_RESUME 的事務只有 NewIntentItem
,其 excute 方法程式碼片段如下:
NewIntentItem.java public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent"); client.handleNewIntent(r, mIntents); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); }
它最終會呼叫到 activity的performNewIntent
方法。
可以看到在這個過程中並沒有涉及到生命週期狀態的轉換。因此,google這段邏輯的意圖是:在執行最終狀態為ON_RESUME的事務時,先將activity生命週期狀態轉換到ON_RESUME的臨近狀態,即ON_START或ON_PAUSE狀態,然後再去執行事務,最後在事務執行完畢後,將activity的狀態真正地切換到ON_RESUME。
第六步,跳過最後一個狀態轉換,改為通過顯式狀態變換去執行。
這裡做了一個判斷,如果事務組最後一次最終狀態與事務集的生命週期狀態相同,跳過此事務的最終狀態的轉換,改由 LifeCycle事務去執行狀態轉換。
然而,我們來看這樣一組事務,ConfigurationChangeItem、NewIntentItem、ConfigurationChangeItem、NewIntentItem,雖然實際編碼中並不會寫出這樣一組事務,但仍可以用來吐槽一下google的這段程式碼邏輯:
由第二步可知,上述的的事務組最後一次activity狀態轉換的Callback索引為 1。
final boolean shouldExcludeLastTransition = i == lastCallbackRequestingState && finalState == postExecutionState; cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);
可以看到,在第二個事務,activity並不會切換到ON_RESUME狀態。
然而這段程式碼最大的問題是,這個判斷並不能達成顯式狀態變換的目標,因為在第四個事務時 activity會被切換到ON_REUSME的目標狀態。
有讀者可能會提出異議了,作者你舉的這個例子是屬於特例,程式碼中不可能這麼寫。 然而,如果不需要考慮這種特殊情況的話,第二步的索引值計算又有什麼作用呢?
這個方法是對事務集中的LifeCycle事務的處理,其程式碼具體如下:
private void executeLifecycleState(ClientTransaction transaction) { ... // Cycle to the state right before the final requested state. cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction); // Execute the final transition with proper parameters. lifecycleItem.execute(mTransactionHandler, token, mPendingActions); lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions); }
可以看到,cycleToPath
是將activity切換到目標生命週期狀態的關鍵方法:
private void cycleToPath(ActivityClientRecord r, int finish, boolean excludeLastState, ClientTransaction transaction) { final int start = r.getLifecycleState(); final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState); performLifecycleSequence(r, path, transaction); }
getLifecyclePath
是獲取狀態路徑的方法,關於狀態路徑在上文中已經有所介紹。
private void performLifecycleSequence(ActivityClientRecord r, IntArray path, ClientTransaction transaction) { final int size = path.size(); for (int i = 0, state; i < size; i++) { state = path.get(i); switch (state) { case ON_CREATE: mTransactionHandler.handleLaunchActivity(r, mPendingActions, null /* customIntent */); break; case ON_START: mTransactionHandler.handleStartActivity(r, mPendingActions, null /* activityOptions */); break; case ON_RESUME: mTransactionHandler.handleResumeActivity(r, false /* finalStateRequest */, r.isForward, "LIFECYCLER_RESUME_ACTIVITY"); break; case ON_PAUSE: mTransactionHandler.handlePauseActivity(r, false /* finished */, false /* userLeaving */, 0 /* configChanges */, mPendingActions, "LIFECYCLER_PAUSE_ACTIVITY"); break; case ON_STOP: mTransactionHandler.handleStopActivity(r, 0 /* configChanges */, mPendingActions, false /* finalStateRequest */, "LIFECYCLER_STOP_ACTIVITY"); break; case ON_DESTROY: mTransactionHandler.handleDestroyActivity(r, false /* finishing */, 0 /* configChanges */, false /* getNonConfigInstance */, "performLifecycleSequence. cycling to:" + path.get(size - 1)); break; case ON_RESTART: mTransactionHandler.performRestartActivity(r, false /* start */); break; default: throw new IllegalArgumentException("Unexpected lifecycle state: " + state); } } } }
獲取到狀態路徑後,開始遍歷路徑,按順序依次切換路徑中的activity生命週期狀態,直到到達目標狀態為止。
在達到目標路徑後,會呼叫Lifecycle事務的excute方法。這裡會再一次呼叫切換到目標狀態的邏輯,不過實際狀態切換時,原始碼裡做了狀態判重的操作,並不會造成任何不良的影響。
以上就是Android10 使用者端事務管理ClientLifecycleManager原始碼解析的詳細內容,更多關於Android10 使用者端事務管理的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45