忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。
-- 服装学院的IT男
ShellTransitions 在 Android 14 开始替代了之前的 AppTransition 正好最近遇到了相关问题,做一些简单的梳理。
建议阅读顺序:
ShellTransitions-2-requestStartTransition处理
1. 概述
“Shell”是处理人机交互的方式,而在安卓系统中 SystemUI 负责整个系统界面的显示和交互,所以 google 设计了个 “WMShell” 放在 SystemUI 端执行,比如最常见的分屏操作。 而窗口的核心处理逻辑还是在 system_server 端,称之为“WMCore”。
在 Android 14 中,google 将之前的 AppTransition 逻辑替换成了 ShellTransitions 。
AppTransition 的作用可以理解为负责 Activity 切换操作的过渡事务处理
之前分析过桌面冷启动应用的所有动画效果,其中就有 AppTransition 参与的动画(app_transition 类型动画),在 Android 14 中这部分的逻辑变为了 ShellTransitions ,执行动画的进程也由之前桌面执行远端动画变成了现在的由 SystemUI 执行动画。
后续的分析还是以冷启动为场景,对比的是之前版本的 AppTransition 逻辑,也就是“app_transition”动画。
其他类型的 Activity 切换场景总体思路也是类似的。
1.1 图层变化
在 Android 14 的版本中,冷启动应用动画开始时会出现"Transition Root: Task=XXX"图层,以前的动画图层名字为 “animation-leash of app_transition ”。 现在的图层的嵌套也和之前有区别,之前是动画图层下面只有新启动应用的 Task ,现在的版本则是把桌面的 Task 也挂载到下面了。
随着动画的执行,发现"Transition Root: Task=XXX"动画图层并没有任何的变化,动画改变的是内部的 Task ,这点和以前也不同。
动画结束后,移除动画图层,恢复到动画前的层级关系,这步是一样的
经过这3张图可以看出来新版本动画还是有明细差别的,从视觉体现也很明显,Android 14 的动画就是简单的淡入移出,这个写个 APP 的人都知道,就是简单的 Activity 切换动画。 而之前 Android 13 的冷启动动画和 iPhone 一样是从桌面图标慢慢放大的效果。所以从视觉体验来说,我个人觉得 Android 14 反而不如之前。
当然最大的区别在于之前的动画是远端动画,在桌面进程播放,现在是在 SystemUI 播放。
1.2 总体流程
可以看到一共有 2 次 WMCore -> WMShell 和 2次 WMShell -> WMCore 的操作。 流程从 system_server 开始,也在 system_server 结束。 动画的播放在 SystemUI 端 。
2.与同步引擎配合使用
这里说的同步引擎指的是 BLASTSyncEngine ,本来是服务于分屏逻辑的。分屏操作涉及到2个应用,为了避免显示异常,所以引入了 BLASTSyncEngine 来控制2个应用的 SurfaceControl.Transaction 一起提交。
在 Android 14 的版本中看到 BLASTSyncEngine 也被应用到了 ShellTransitions 中。
为了避免减少阅读困难,所以 ShellTransitions 的分析中封装了 BLASTSyncEngine 相关的逻辑,建议阅读本系列前先了解 BLASTSyncEngine的工作逻辑。
3. 相关状态装类介绍
3.1 容器同步状态
# WindowState
/** This isn't participating in a sync. */
// 没有参与同步
public static final int SYNC_STATE_NONE = 0;
/** This is currently waiting for itself to finish drawing. */
// 等待绘制
public static final int SYNC_STATE_WAITING_FOR_DRAW = 1;
/** This container is ready, but it might still have unfinished children. */
// 此容器已准备就绪,但可能仍有未完成的子容器
public static final int SYNC_STATE_READY = 2;
@IntDef(prefix = { "SYNC_STATE_" }, value = {
SYNC_STATE_NONE,
SYNC_STATE_WAITING_FOR_DRAW,
SYNC_STATE_READY,
})
@interface SyncState {}
3.2 过渡事务状态
# Transition
/** The transition has been created but isn't collecting yet. */
// 刚创建状态, 只是创建了过渡事务,但是还没开始收集
private static final int STATE_PENDING = -1;
/** The transition has been created and is collecting, but hasn't formally started. */
// 过渡事务正在收集参与动画的容器,但动画尚未正式开始
private static final int STATE_COLLECTING = 0;
/**
* The transition has formally started. It is still collecting but will stop once all
* participants are ready to animate (finished drawing).
*/
// 事务已经启动,但是还处于收集状态
// 停止收集的条件是:所有参与者完成绘制(准备完毕)
private static final int STATE_STARTED = 1;
/**
* This transition is currently playing its animation and can no longer collect or be changed.
*/
// 已经开始播放过渡动画
// 这种状态自然也不再收集了
private static final int STATE_PLAYING = 2;
/**
* This transition is aborting or has aborted. No animation will play nor will anything get
* sent to the player.
*/
// 中止状态
// 不再播放动画
private static final int STATE_ABORT = 3;
/**
* This transition has finished playing successfully.
*/
// 过渡动画播放完毕
private static final int STATE_FINISHED = 4;
@IntDef(prefix = { "STATE_" }, value = {
STATE_PENDING,
STATE_COLLECTING,
STATE_STARTED,
STATE_PLAYING,
STATE_ABORT,
STATE_FINISHED
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionState {}
private @TransitionState int mState = STATE_PENDING;
4. 总体流程结束
调用链和流程图如下:
堆栈:
ActivityStarter::startActivityUnchecked
TransitionController::createAndStartCollecting
Transition::init -- 创建过渡事务 STATE_PENDING
TransitionController::moveToCollecting -- 设置为主事务
Transition::startCollecting -- STATE_COLLECTING
BLASTSyncEngine::startSyncSet -- 创建同步组
TransitionController::collect
Transition::collect
BLASTSyncEngine::addToSyncSet -- 收集 ActivityRecord
ChangeInfo::init
ActivityStarter::startActivityInner
ActivityStarter::getOrCreateRootTask
ActivityStarter::setNewTask
TransitionController::collectExistenceChange -- 记录 Task 存在性变化
Transition::collect
BLASTSyncEngine::addToSyncSet -- 收集 Task
ActivityStarter::handleStartResult
TransitionController::collectExistenceChange -- 记录 ActivityRecord 存在性变化
Transition::collect
TransitionController::requestStartTransition -- WMCore -> WMShell 第一次
Transitions::requestStartTransition
ActiveTransition::init
TransitionHandler::handleRequest -- 找到处理对应动画的TransitionHandler
WindowOrganizer::startTransition -- WMShell -> WMCore 第一次
WindowOrganizerController::startTransition
WindowOrganizerController::startTransition
Transition::start -- STATE_STARTED
Transition::applyReady
Transition::allReady
BLASTSyncEngine::setReady
SyncGroup::setReady -- 设置同步组准备状态(false)
mPendingTransitions::add
executeAppTransition 流程设置同步组准备就绪
RootWindowContainer::performSurfacePlacementNoTrace -- 检查直至同步完成
BLASTSyncEngine::onSurfacePlacement
Transition::onTransactionReady -- STATE_PLAYING
TransitionPlayerImpl::onTransitionReady -- WMCore -> WMShell 第二次
Transitions::onTransitionReady
Transitions::processReadyQueue
Transitions::playTransition
Transitions::dispatchTransition
DefaultTransitionHandler::startAnimation
DefaultTransitionHandler::loadAnimation -- 加载动画资源
DefaultTransitionHandler::buildSurfaceAnimation -- 构建动画
SurfaceControl.Transaction::apply -- startTransaction
Animator::start -- 开始动画
DefaultTransitionHandler::applyTransformation
Transitions::onFinish -- 动画结束
SurfaceControl.Transaction::apply -- finishTransaction
WindowOrganizer::finishTransition WMShell -> WMCore 第二次
WindowOrganizerController::finishTransition
ransition::finishTransition -- STATE_FINISHED
这个系列的文章目前只介绍了总体流程,一些细节还不清楚 google 为什么要这么做,所以这个系列后续会修订提高质量。
目前 ShellTransitions 的文章网上文章不多,所以先放出来,有意见的欢迎一起探讨。
参考链接: