亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android客戶端事務管理ClientLifecycleManager源碼分析

發布時間:2022-10-12 10:20:17 來源:億速云 閱讀:155 作者:iii 欄目:開發技術

本篇內容主要講解“Android客戶端事務管理ClientLifecycleManager源碼分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Android客戶端事務管理ClientLifecycleManager源碼分析”吧!

正文

生命周期管理是google在Android 9才引入的設計,在Android 9之前,activity 存在生命周期的概念,但并無生命周期管理這一說法。為了方便生命周期的切換以及相關業務的管理,google采用了事務的思想,將生命周期抽象為客戶端事務的一部分來統一管理。下圖是客戶端事務管理完整的UML圖:

Android客戶端事務管理ClientLifecycleManager源碼分析

相關類說明:

  • ClientLifecycleManager: 客戶端事務管理類,包括且不限于處理Activity生命周期轉換事務,同時也包括 與客戶端相關的其他事務處理。

  • ClientTransaction:事務集類,一個事務集可以存放一系列Callback事務及一個生命周期事務。

  • TransactionExecutor:事務執行器,讓事務以正確的順序執行。

  • BaseClientRequest :事務的抽象類,定義了preExecuteexecutepostExecute三個接口,分別代表事務執行前、執行中、執行后三個階段的回調方法。

  • ActivityLifecycleItem:abstract class,Activity生命周期事務類,其子類有DestroyActivityItemPauseActivityItemStopActivityItemResumeActivityItem,表示具體的activity生命周期轉換事務。

  • ClientTransactionItem:abstract class,客戶端事務類,ActivityLifecycleItem是它的子類之一。除此之外,還有如下內置的客戶端事務:

Transaction NameDesc
ConfigurationChangeItemApp configuration 改變的消息
WindowVisibilityItemWindow可見性發生改變的消息
MoveToDisplayItemActivity 移動到不同的顯示設備的消息
MultiWindowModeChangeItem多窗口模式改變的消息
ActivityConfigurationChangeItemActivity configuration 改變的回調
PipModeChangeItem畫中畫模式改變的消息
ActivityResultItemActivity result的回調
NewIntentItemNew intent消息
TopResumedActivityChangeItemTop resumed activity 改變的回調
ActivityRelaunchItem重啟Activity的回調
LaunchActivityItem請求啟動一個Activity

ClientLifecycleManager

ClientLifecycleManagerActivityTaskManagerService中初始化了唯一的實例,所有的事務操作,必須通過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

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負責后續的邏輯處理。

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特殊處理的邏輯,不太重要,我們忽略它。

我們分別來看一下executeCallbacksexecuteLifecycleState兩個方法。

 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);
            }
        }
    }

上述代碼主要做了以下幾件事:

  • 獲取事務集的target lifecycle。

  • 獲取事務集中最后一次Activity生命周期轉換的Callback索引。

  • 遍歷所有的Callback事務。

  • 獲取Callback事務的結束狀態值,如結束狀態值為onResume,檢查Activity當前狀態,判斷當前的就近狀態(onStart/onPause),并將activity轉換到就近狀態。

  • 執行Callback事務的execute和postExecute邏輯。

  • 跳過最后一個狀態轉換,改為通過顯式狀態變換去執行。

google這段邏輯寫的極為繁雜啰嗦,讓人吐槽的點實在太多了,但還是要在此講一下它是怎么設計的,源碼中又哪里糟點。

首先是事務集的target lifecycle,它指的是事務集中唯一的Lifecycle事務(如果存在的話)的狀態,表示事務集執行完畢后,Activity最終的生命周期狀態。

第二點,事務集中最后一次Activity生命周期轉換的Callback索引,這句話是什么含義呢?

Callback事務中有這么一個方法,getPostExecutionState,它表示在當前Callback事務執行完畢后Activity所需處于的生命周期狀態,為方便敘述,下文稱其為結束狀態。將Callback事務列表從后向前遍歷,如果當前事務存在結束狀態(即getPostExecutionState的值不為UNDEFINED),且與上一個結束狀態相同,記錄下此時事務在列表中的索引值,直到當前結束狀態與上一個狀態不同為止。此時,上一個事務的索引值即為事務集中最后一次Activity生命周期轉換的Callback索引

假如某事務集有這樣一組Callback事務&mdash;&mdash;ConfigurationChangeItem、NewIntentItem、ConfigurationChangeItem、NewIntentItem。其中ConfigurationChangeItem的結束狀態為UNDEFINED,NewIntentItem的結束狀態為ON_RESUME。

我們從后向前開始遍歷:

  • 最后一個事務為 NewIntentItem,結束狀態為ON_RESUME,記錄下此時的索引值 3。

  • 倒數第二個事務為 ConfigurationChangeItem,不存在結束狀態,跳過。

  • 倒數第三個事務為 NewIntentItem,結束狀態為ON_RESUME,上一個結束狀態同樣也是 ON_RESUME,更新索引值 為 1。

  • 倒數第四個事務為 ConfigurationChangeItem,不存在結束狀態,跳過。

因此,此事務集中最后一次Activity生命周期轉換的Callback索引 為1。至于這個索引值有什么意義呢,待會再解釋。

然而,這段設計中還是有幾點需要吐槽一下:

  • google官方在注釋中舉例的 事務是 Configuration - ActivityResult - Configuration - ActivityResult , 并且說明ActivityResult 的結束狀態為RESUMED。讓我們看看ActivityResultItem的源碼:

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~~~~。

  • 設計歸設計,到android13 為止,framework里從來沒有過一個事務集里綁定多個Callback事務的用法,所以 這段邏輯設計的并沒有什么用。

第四點,如果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;

狀態之間的轉換路徑如下表所示:

Android客戶端事務管理ClientLifecycleManager源碼分析

上表中置灰的單元格,表示不存在或禁止的狀態轉換,而單元格中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的目標狀態。

有讀者可能會提出異議了,作者你舉的這個例子是屬于特例,代碼中不可能這么寫。 然而,如果不需要考慮這種特殊情況的話,第二步的索引值計算又有什么作用呢?

executeLifecycleState

這個方法是對事務集中的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方法。這里會再一次調用切換到目標狀態的邏輯,不過實際狀態切換時,源碼里做了狀態判重的操作,并不會造成任何不良的影響。

到此,相信大家對“Android客戶端事務管理ClientLifecycleManager源碼分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

博湖县| 宁安市| 德化县| 宁城县| 巍山| 岱山县| 吉林市| 措美县| 惠来县| 阿巴嘎旗| 高雄县| 芜湖县| 出国| 军事| 九台市| 泸州市| 定日县| 轮台县| 望都县| 定兴县| 疏勒县| 巧家县| 湖南省| 定陶县| 永吉县| 桑日县| 阜南县| 望城县| 威宁| 双桥区| 阜康市| 许昌县| 凤城市| 灵武市| 鲁山县| 金塔县| 五河县| 稻城县| 达拉特旗| 潞西市| 宜黄县|