在Android 10 App启动分析之Activity启动篇(二)一文中,简单地介绍了Activity的生命周期管理器是如何调度Activity进入onCreate生命周期的流程。这篇文章,我们将详细地分析framework中activity的生命周期管理功能,从更宏观的角度来更全面地了解生命周期及相关事务的工作原理。
生命周期管理是google在Android 9才引入的设计,在Android 9之前,activity 存在生命周期的概念,但并无生命周期管理这一说法。为了方便生命周期的切换以及相关业务的管理,google采用了事务的思想,将生命周期抽象为客户端事务的一部分来统一管理。下图是客户端事务管理完整的UML图:
相关类说明:
- ClientLifecycleManager: 客户端事务管理类,包括且不限于处理Activity生命周期转换事务,同时也包括 与客户端相关的其他事务处理。
- ClientTransaction:事务集类,一个事务集可以存放一系列Callback事务及一个生命周期事务。
- TransactionExecutor:事务执行器,让事务以正确的顺序执行。
- BaseClientRequest :事务的抽象类,定义了preExecute、execute、postExecute三个接口,分别代表事务执行前、执行中、执行后三个阶段的回调方法。
- ActivityLifecycleItem:abstract class,Activity生命周期事务类,其子类有DestroyActivityItem、PauseActivityItem、StopActivityItem、ResumeActivityItem,表示具体的activity生命周期转换事务。
- ClientTransactionItem:abstract class,客户端事务类,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
ClientLifecycleManager在ActivityTaskManagerService中初始化了唯一的实例,所有的事务操作,必须通过ATMS中的实例来发起。如: mService.getLifecycleManager().scheduleTransaction(clientTransaction);。
ClientLifecycleManager的源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
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方法非常简单,代码如下所示:
1
2
3
|
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}
|
上述代码片段中的mClient到底指的是什么?
从源码的角度来看,mClient 是 ApplicationThread的一个实例。而 ApplicationThread 是ActivityThread的一个内部类,作为ActivityThread 与外部沟通的桥梁。所有的事务集最终都会被派发到ActivityThread中统一处理。
1
2
3
4
5
|
ActivityThread.java
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
|
ActivityThread里首先调用了ClientTransaction中的preExecute方法,代码片段如下:
1
2
3
4
5
6
7
8
9
10
11
|
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,内容如下:
1
2
3
4
|
mTransactionExecutor.execute(transaction);
if (isSystem()) {
transaction.recycle();
}
|
接下来由TransactionExecutor负责后续的逻辑处理。
TransactionExecutor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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两个方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
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事务——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的源码:
1
2
3
4
5
6
7
8
9
|
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定义了九种状态,具体如下:
1
2
3
4
5
6
7
8
|
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,具体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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 方法代码片段如下:
1
2
3
4
5
6
7
|
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。
1
2
3
|
final boolean shouldExcludeLastTransition =
i == lastCallbackRequestingState && finalState == postExecutionState;
cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);
|
可以看到,在第二个事务,activity并不会切换到ON_RESUME状态。
然而这段代码最大的问题是,这个判断并不能达成显式状态变换的目标,因为在第四个事务时 activity会被切换到ON_REUSME的目标状态。
有读者可能会提出异议了,作者你举的这个例子是属于特例,代码中不可能这么写。 然而,如果不需要考虑这种特殊情况的话,第二步的索引值计算又有什么作用呢?
executeLifecycleState
这个方法是对事务集中的LifeCycle事务的处理,其代码具体如下:
1
2
3
4
5
6
7
8
|
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切换到目标生命周期状态的关键方法:
1
2
3
4
5
6
|
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是获取状态路径的方法,关于状态路径在上文中已经有所介绍。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
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方法。这里会再一次调用切换到目标状态的逻辑,不过实际状态切换时,源码里做了状态判重的操作,并不会造成任何不良的影响