Android 14 ShellTransitions 动画参与者收集全解析:从Activity启动到App切换的幕后逻辑

张开发
2026/4/15 22:16:50 15 分钟阅读

分享文章

Android 14 ShellTransitions 动画参与者收集全解析:从Activity启动到App切换的幕后逻辑
Android 14 ShellTransitions动画参与者收集机制深度解析在Android 14的窗口管理系统中ShellTransitions框架扮演着关键角色它负责协调和管理应用切换、Activity启动等场景下的过渡动画。理解动画参与者的收集机制对于开发者优化应用启动性能、定制系统动画效果具有重要意义。本文将深入剖析从Activity启动到App切换过程中系统如何识别、筛选和组织动画参与者揭示WindowContainer同步与状态管理的核心逻辑。1. ShellTransitions框架概览ShellTransitions是Android 14引入的全新窗口过渡动画框架它重构了传统的动画处理流程采用更加模块化和可扩展的设计。与早期版本相比最大的变化在于将动画逻辑从WindowManagerService中解耦交由独立的Shell组件处理。框架的核心工作流程可以分为三个阶段收集阶段(COLLECTING)识别并注册所有参与动画的窗口容器准备阶段(PREPARING)等待所有参与者完成绘制等准备工作执行阶段(STARTED)实际执行动画效果在这个过程中三个关键数据结构协同工作SyncGroup管理需要同步的窗口容器集合ChangeInfo记录窗口容器在动画前后的状态变化Transition封装完整的动画流程和参与者信息// 伪代码展示Transition基本结构 class Transition { int mState; // COLLECTING/PREPARING/STARTED ArraySetWindowContainer mParticipants; MapWindowContainer, ChangeInfo mChanges; SyncGroup mSyncGroup; }2. 动画参与者收集触发时机动画参与者的收集并非随意进行而是严格遵循特定的触发条件和执行路径。系统通过TransitionController来协调整个收集过程。2.1 主要触发场景在实际使用中以下几种用户操作会启动动画参与者收集应用启动点击Launcher图标启动新应用应用切换通过最近任务键或手势导航切换应用返回桌面按Home键返回Launcher分屏操作进入或退出分屏模式窗口模式变更全屏/自由窗口切换2.2 核心调用链路无论哪种场景收集过程的代码执行路径都遵循相似的模式ActivityStarter.startActivityUnchecked() → TransitionController.createAndStartCollecting() → TransitionController.collect() → Transition.collect()这个调用链的关键在于createAndStartCollecting()初始化Transition对象并设置状态为COLLECTINGcollect()方法实际执行参与者注册逻辑状态检查机制Transition.collect()首先会验证当前状态只有处于COLLECTING或STARTED状态的Transition才能接收新的参与者。这种设计确保了动画生命周期的严谨性。// 状态检查逻辑示例 if (mState STATE_COLLECTING) { throw new IllegalStateException(Transition not collecting); } if (mState STATE_STARTED) { return; // 太晚不再收集 }3. 参与者筛选与同步机制不是所有WindowContainer都会成为动画参与者。系统通过一套精细的筛选逻辑确定哪些容器需要参与同步和动画。3.1 needSync决策树决定是否将WindowContainer加入SyncGroup的关键条件是needSyncneedSync !(windowContainer is WallpaperWindowToken) (displayContent已包含在参与者中 || !windowContainer被Recents遮挡)这个条件确保了壁纸窗口有特殊处理只有可见或即将可见的窗口才会参与同步避免收集被临时遮挡的窗口3.2 BLAST同步引擎工作流程当needSync为true时系统会通过BLASTSyncEngine管理窗口容器的同步状态添加到SyncSet将WindowContainer与特定Transition关联设置同步状态非WindowState容器如Task、ActivityRecord直接标记为READYWindowState需要等待绘制完成才会转为READY// SyncGroup添加参与者的核心逻辑 void addToSync(WindowContainer wc) { if (wc.getSyncGroup() null) { mRootMembers.add(wc); wc.setSyncGroup(this); } wc.prepareSync(); }3.3 同步状态机WindowContainer的同步状态遵循严格的转换规则状态含义转换条件SYNC_STATE_NONE未参与同步初始状态SYNC_STATE_WAITING_FOR_DRAW等待绘制完成WindowState被添加时SYNC_STATE_READY准备就绪绘制完成或非WindowState容器对于开发者而言理解这个状态机有助于诊断动画卡顿问题。例如如果某个WindowState长时间停留在WAITING_FOR_DRAW状态通常意味着该窗口的绘制出现了问题。4. 参与者信息记录与变更追踪除了同步管理外Transition框架还详细记录每个参与者的状态变化这是实现高质量动画的基础。4.1 ChangeInfo的作用机制ChangeInfo对象保存了WindowContainer在动画开始前的关键状态用于后续计算动画参数。其工作流程如下收集阶段创建ChangeInfo快照变更阶段窗口实际发生变化准备阶段对比前后状态计算动画参数// ChangeInfo创建示例 ChangeInfo info new ChangeInfo(windowContainer); mChanges.put(windowContainer, info); // 后续比较变化 void onTransactionReady() { ChangeInfo before mChanges.get(windowContainer); WindowContainer current getCurrentState(); // 比较before和current计算动画 }4.2 多层级参与者收集系统不仅收集直接操作的WindowContainer还会向上遍历其层级结构收集可能需要参与动画的父容器Activity启动收集新ActivityRecord及其TaskApp切换收集前后应用的Task及其TaskDisplayArea显示变更可能涉及DisplayContent级别的调整这种设计确保了复杂场景下如分屏、自由窗口动画的完整性。4.3 三种参与者集合对比理解不同集合的包含关系和用途对调试动画问题很有帮助集合包含内容用途mParticipants所有直接操作的WindowContainer动画目标识别mRootMembers需要通过BLAST同步的容器绘制同步管理mChanges直接参与者可能受影响的父容器状态变化追踪典型情况下mRootMembers ⊆ mParticipants ⊆ mChanges.keySet()5. 实际场景下的参与者收集分析通过具体用例可以更直观地理解收集机制的实际运作。5.1 应用启动场景从Launcher启动新应用的流程最为典型初始状态只有Launcher Task存在创建阶段新建ActivityRecord和Task收集过程新ActivityRecord被加入mParticipants由于是新创建其父Task尚未关联不触发needSync仅为ActivityRecord创建ChangeInfo// 伪代码展示启动场景 ActivityRecord newActivity createActivity(); transition.collect(newActivity); // newActivity.getParent() null → 仅基础收集5.2 应用切换场景从应用A切换到应用B的流程更为复杂收集应用A的Task加入mParticipants和mRootMembers向上收集TaskDisplayArea和DisplayContent的ChangeInfo收集应用B的Task同样记录多层级信息结果mParticipants包含两个TaskmChanges包含从Task到DisplayContent的完整层级// 伪代码展示应用切换 Task taskA getCurrentTask(); Task taskB getNextTask(); transition.collect(taskA); // 收集层级结构 transition.collect(taskB); // 收集层级结构5.3 分屏操作场景分屏模式下的参与者收集展示了框架处理复杂场景的能力进入分屏收集主窗口和分屏窗口的Task收集共享的TaskDisplayArea特殊处理分割线控件调整分屏比例需要重新收集受影响窗口计算新旧尺寸的ChangeInfo这种场景下mChanges通常会包含更多层级的WindowContainer因为分屏操作会影响整个显示区域的布局。6. 性能优化与调试技巧理解参与者收集机制后开发者可以更好地优化应用动画性能。6.1 常见性能瓶颈根据收集流程动画延迟通常源于绘制延迟WindowState长时间处于WAITING_FOR_DRAW优化减少主线程工作避免过度绘制同步等待多个WindowContainer就绪时间不一致优化简化视图层次提前初始化资源过度收集不必要的大型容器被纳入动画优化合理设置窗口属性避免全局重排6.2 调试工具与方法Android提供多种工具观察参与者收集# 查看当前Transition状态 adb shell dumpsys window transitions # 跟踪特定WindowContainer adb shell dumpsys window windows | grep -A10 WindowContainer关键检查点参与者的同步状态是否按预期变化ChangeInfo记录的前后状态差异收集过程中是否有异常跳过或重复6.3 最佳实践建议启动优化减少Application和首屏Activity的初始化工作过渡提示使用setActivityTransitionInfo提供准确的共享元素信息窗口属性正确设置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS等标志避免突变在动画期间保持视图结构稳定在实际项目中我曾遇到一个案例应用在启动时因加载大量数据导致动画卡顿。通过分析发现主窗口的绘制准备时间过长处于WAITING_FOR_DRAW状态超过300ms。解决方案是将数据加载移到后台线程并优先完成必要的视图初始化最终将动画延迟降低到可接受范围。

更多文章