恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
第 14 章:动画系统
首页
资讯中心
/
第 14 章:动画系统
第 14 章:动画系统
发布时间:2026/8/13 23:59:18
Android 的动画系统历经四代 API 的演进,每一代都支持范围更广的运动效果 —— 从简单的视图级别变换,到基于物理的弹簧模型,再到窗口管理器的协同壳层转场动画。本章完整追踪动画数值从应用代码到合成器的整条执行路径,详细剖析各个主要子系统,并说明各模块如何通过 Choreographer 基于 VSYNC 的时序脉冲完成协同工作。14.1 动画架构概述14.1.1 四代动画Android 提供四层独立的动画体系,每一层都构建在上一层基础之上:代API 等级包 / 位置作用域视图动画(遗留)1android.view.animation单个 View 的矩阵 + 透明度属性动画11android.animation任意 Object 对象的任意类型属性转场框架19android.transitionViewGroup 范围内的场景变更编排壳层转场12L+com.android.wm.shell.transition跨窗口、跨任务的窗口管理器转场除此之外,平台还提供专用子系统实现基于物理的运动(DynamicAnimation、SpringAnimation、FlingAnimation)、原生 RenderThread 动画(HWUI)以及 Drawable 层级动画(AnimatedVectorDrawable)。14.1.2 端到端动画数据流壳进程 系统服务窗口管理器 RenderThread 应用进程14.1.3 时序基础设施UI 线程上的全部动画共用同一个时序源:Choreographer。Choreographer 接收显示子系统的 VSYNC 信号,每一帧按顺序分发五类回调:// frameworks/base/core/java/android/view/Choreographer.java,第321‑363行 CALLBACK_INPUT = 0 // 输入事件 CALLBACK_ANIMATION = 1 // 动画器帧回调 CALLBACK_INSETS_ANIMATION = 2 // 窗口Insets动画更新 CALLBACK_TRAVERSAL = 3 // View测量/布局/绘制 CALLBACK_COMMIT = 4 // 绘制完成提交;上报修正后的帧起始时间CALLBACK_COMMIT 阶段在视图遍历完成后执行,提供更准确的帧起始时间估算,视图层级可用来补偿复杂布局带来的延迟。注意:Android 17 中 AnimationHandler 不再为每个动画器单独注册 commit 回调;早期版本附加在每个 ValueAnimator 上的启动时间修正 / 卡顿补偿钩子已被移除(参见 §14.3.12)。AnimationHandler 向 Choreographer 注册一个 FrameCallback,每次 VSYNC 到来时遍历所有已注册的 AnimationFrameCallback 实例,其中包含所有正在运行的 ValueAnimator 与 DynamicAnimation。14.1.4 核心源码目录目录内容大致代码行数frameworks/base/core/java/android/view/animation/视图动画类~5800frameworks/base/core/java/android/animation/属性动画框架~13400frameworks/base/core/java/android/transition/转场框架~9200frameworks/base/libs/hwui/ (Animator*)原生 HWUI 动画器~830frameworks/base/core/java/android/view/Choreographer.java时序脉冲1741frameworks/base/services/core/java/com/android/server/wm/ (anim)窗口管理器动画基础设施~2400frameworks/base/libs/WindowManager/Shell/src/.../transition/壳层转场~8200frameworks/base/libs/WindowManager/Shell/src/.../back/预测返回手势~3200frameworks/base/core/java/com/android/internal/dynamicanimation/animation/物理动画~175014.1.5 线程模型分析性能时,必须清楚每一类动画运行在哪一个线程:关键点:ViewPropertyAnimator 与 AnimatedVectorDrawable(API25+)在 RenderThread 原生执行,不受 UI 线程卡顿影响。其余所有 Java 层动画均运行在 UI 线程,会受 GC、繁重布局或其他主线程任务干扰。14.1.6 跨进程动画协同现代 Android 动画经常跨多个进程:动画逻辑运行在壳进程,但作用于应用进程的 Surface。这种解耦保证应用卡顿不会影响系统转场动画。14.1.7 动画时长与缩放系数Android 所有动画均受全局动画缩放配置控制。共有三个独立缩放因子:配置项作用对象默认值animator_duration_scale属性动画(ValueAnimator 等)1.0window_animation_scale窗口打开 / 关闭动画1.0transition_animation_scaleActivity 转场动画1.0可通过开发者选项或命令行修改:adb shell settings put global animator_duration_scale 2.0 adb shell settings put global window_animation_scale 0.5 adb shell settings put global transition_animation_scale 0任意一项设置为 0,对应动画直接禁用,瞬间完成。14.1.8 帧预算60Hz 下单帧预算16.67ms;120Hz 下单帧预算8.33ms。动画回调必须在预算的一小部分内完成,给布局、绘制、GPU 留出时间。阶段60Hz 预算120Hz 预算INPUT 回调~1ms~0.5msANIMATION 回调~2ms~1msINSETS_ANIMATION~0.5ms~0.3msTRAVERSAL(布局 + 绘制)~10ms~5msGPU 渲染~3ms~1.5ms合计~16.5ms~8.3ms超出预算会发生掉帧(卡顿)。Choreographer 跳过超过 30 帧时会输出警告日志。14.2 视图动画(遗留)14.2.1 概述视图动画从 API 1 开始存在,在绘制阶段给 View 应用 Transformation(矩阵 + 透明度)。重要特性:视图动画不会修改 View 真实布局属性;一个做平移动画的 View,触摸事件仍在原始位置响应。源码目录:frameworks/base/core/java/android/view/animation/(共 29 个文件)14.2.2 Animation 基类抽象类 Animation(1363 行)定义动画生命周期:// frameworks/base/core/java/android/view/animation/Animation.java,第40‑98行 public abstract class Animation implements Cloneable { public static final int INFINITE = -1; public static final int RESTART = 1; public static final int REVERSE = 2; public static final int START_ON_FIRST_FRAME = -1; public static final int ABSOLUTE = 0; public static final int RELATIVE_TO_SELF = 1; public static final int RELATIVE_TO_PARENT = 2; public static final int ZORDER_NORMAL = 0; public static final int ZORDER_TOP = 1; public static final int ZORDER_BOTTOM = -1; ... }核心内部状态(第 110‑237 行)字段类型用途mEndedbooleangetTransformation () 在动画结束时置位mStartedboolean第一帧时置位mCycleFlipbooleanREVERSE 重复模式下切换状态mInitializedboolean播放前必须为 truemFillBeforeboolean动画开始前应用变换(默认 true)mFillAfterboolean动画结束后保持变换mStartTimelong绝对起始时间,单位毫秒mDurationlong单次周期时长mRepeatCountint重复次数(0 = 播放一次)mRepeatModeintRESTART 或 REVERSEmInterpolatorInterpolator缓动曲线mScaleFactorfloat锚点缩放系数生命周期由getTransformation(long, Transformation)驱动:计算流逝时间、应用插值器,调用抽象方法applyTransformation(float interpolatedTime, Transformation t)。14.2.3 TransformationTransformation 类(32‑80 行)封装视图动画输出结果:// frameworks/base/core/java/android/view/animation/Transformation.java,第32‑48行 public class Transformation { public static final int TYPE_IDENTITY = 0x0; public static final int TYPE_ALPHA = 0x1; public static final int TYPE_MATRIX = 0x2; public static final int TYPE_BOTH = TYPE_ALPHA | TYPE_MATRIX; protected Matrix mMatrix; protected float mAlpha; protected int mTransformationType; ... }Transformation 持有 Matrix(平移 / 旋转 / 缩放)与 alpha 透明度。compose(Transformation)方法将两个变换拼接,AnimationSet 就是依靠该接口组合子动画。14.2.4 具体动画子类AlphaAnimation最简单动画,仅修改透明度分量:// frameworks/base/core/java/android/view/animation/AlphaAnimation.java,第67‑70行 @Override protected void applyTransformation(float interpolatedTime, Transformation t) { final float alpha = mFromAlpha; t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime)); }willChangeTransformationMatrix()返回 false,代表不修改矩阵,仅做透明度混合。TranslateAnimation修改矩阵平移实现 View 移动:// frameworks/base/core/java/android/view/animation/TranslateAnimation.java,第166‑176行 @Override protected void applyTransformation(float interpolatedTime, Transformation t) { float dx = mFromXDelta; float dy = mFromYDelta; if (mFromXDelta != mToXDelta) { dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime); } if (mFromYDelta != mToYDelta) { dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime); } t.getMatrix().setTranslate(dx, dy); }initialize () 解析数值类型:ABSOLUTE:直接使用像素值RELATIVE_TO_SELF:乘以 View 自身尺寸RELATIVE_TO_PARENT:乘以父容器尺寸RotateAnimation围绕可配置锚点旋转:// frameworks/base/core/java/android/view/animation/RotateAnimation.java,第166‑175行 @Override protected void applyTransformation(float interpolatedTime, Transformation t) { float degrees = mFromDegrees + ((mToDegrees - mFromDegrees) * interpolatedTime); float scale = getScaleFactor(); if (mPivotX == 0.0f mPivotY == 0.0f) { t.getMatrix().setRotate(degrees); } else { t.getMatrix().setRotate(degrees, mPivotX * scale, mPivotY * scale); } }ScaleAnimation支持锚点的缩放动画,解析起止值(可以是小数或尺寸):// frameworks/base/core/java/android/view/animation/ScaleAnimation.java,第241‑258行 @Override protected void applyTransformation(float interpolatedTime, Transformation t) { float sx = 1.0f; float sy = 1.0f; float scale = getScaleFactor(); if (mFromX != 1.0f || mToX != 1.0f) { sx = mFromX + ((mToX - mFromX) * interpolatedTime); } if (mFromY != 1.0f || mToY != 1.0f) { sy = mFromY + ((mToY - mFromY) * interpolatedTime); } if (mPivotX == 0 mPivotY == 0) { t.getMatrix().setScale(sx, sy); } else { t.getMatrix().setScale(sx, sy, scale * mPivotX, scale * mPivotY); } }14.2.5 AnimationSetAnimationSet(553 行)用于组合多个同时播放的动画。它的 getTransformation 逆序遍历子动画,调用 compose () 拼接变换:// frameworks/base/core/java/android/view/animation/AnimationSet.java,第390‑423行 @Override public boolean getTransformation(long currentTime, Transformation t) { final int count = mAnimations.size(); final ArrayListAnimation animations = mAnimations; final Transformation temp = mTempTransformation; boolean more = false; boolean started = false; boolean ended = true; t.clear(); for (int i = count - 1; i = 0; --i) { final Animation a = animations.get(i); temp.clear(); more = a.getTransformation(currentTime, temp, getScaleFactor()) || more; t.compose(temp); started = started || a.hasStarted(); ended = a.hasEnded() ended; } ... }duration、fillBefore、fillAfter、repeatMode 等属性可以通过属性标记向下传递给子动画(第 54‑61 行):// AnimationSet.java,第54‑61行 private static final int PROPERTY_FILL_AFTER_MASK = 0x1; private static final int PROPERTY_FILL_BEFORE_MASK = 0x2; private static final int PROPERTY_REPEAT_MODE_MASK = 0x4; private static final int PROPERTY_START_OFFSET_MASK = 0x8; private static final int PROPERTY_SHARE_INTERPOLATOR_MASK = 0x10; private static final int PROPERTY_DURATION_MASK = 0x20; private static final int PROPERTY_MORPH_MATRIX_MASK = 0x40; private static final int PROPERTY_CHANGE_BOUNDS_MASK = 0x80;14.2.6 插值器android.view.animation 包内置 12 种插值器:插值器公式 / 行为典型用途AccelerateDecelerateInterpolatorcos((t+1)*PI)/2 + 0.5默认;自然运动AccelerateInterpolatort^(2*factor)退出动画DecelerateInterpolator1‑(1‑t)^(2*factor)进入动画LinearInterpolatort匀速BounceInterpolator分段二次函数末尾弹跳OvershootInterpolator三次过冲类弹簧效果AnticipateInterpolator先回拉再射出卡通蓄力效果AnticipateOvershootInterpolator蓄力 + 过冲组合组合效果CycleInterpolatorsin(2PIcycles*t)抖动 / 摇摆PathInterpolator自定义贝塞尔 / SVG 路径Material 动效BackGestureInterpolator返回手势曲线预测返回BaseInterpolator抽象基类自定义实现AccelerateDecelerateInterpolator 实现非常简洁:// frameworks/base/core/java/android/view/animation/AccelerateDecelerateInterpolator.java,第39行 public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; }14.2.7 PathInterpolatorAPI21 引入,用于 Material Design 动效。PathInterpolator 将一条从 (0,0) 到 (1,1) 的 Path 映射为插值曲线。路径被离散成 (x,y) 点对,输入 t 通过二分查找得到对应的 y 值。// frameworks/base/core/java/android/view/animation/PathInterpolator.java,第207‑237行 @Override public float getInterpolation(float t) { if (t = 0) return 0; else if (t = 1) return 1; // 二分查找x区间 int startIndex = 0; int endIndex = mX.length - 1; while (endIndex - startIndex 1) { int midIndex = (startIndex + endIndex) / 2; if (t mX[midIndex]) { endIndex = midIndex; } else { startIndex = midIndex; } } float xRange = mX[endIndex] - mX[startIndex]; if (xRange == 0) return mY[startIndex]; float tInRange = t - mX[startIndex]; float fraction = tInRange / xRange; float startY = mY[startIndex]; float endY = mY[endIndex]; return startY + (fraction * (endY - startY)); }支持三种构造方式:二次贝塞尔:PathInterpolator(controlX, controlY),1 个控制点三次贝塞尔:PathInterpolator(cx1, cy1, cx2, cy2),2 个控制点SVG Path Data:XML 属性 pathData,由 PathParser 解析所有插值器实现 NativeInterpolator,为 HWUI RenderThread 动画提供原生句柄。14.2.8 视图动画类继承体系14.2.9 视图动画局限性不修改真实属性:仅做视觉变换。View 的 left、top、width、height 不变,点击检测使用原始边界。仅作用于 View:无法对普通对象、非 View 属性做动画。类型有限:只支持矩阵(平移 / 旋转 / 缩放)和透明度,没有颜色动画,不支持任意类型数值。矩阵乘法组合:AnimationSet 依靠矩阵拼接,复杂多属性协同能力受限。这些局限促使 API11 引入属性动画框架。14.2.10 getTransformation () 核心循环视图动画的核心是逐帧计算变换的 getTransformation (),完整算法(1011‑1079 行):// frameworks/base/core/java/android/view/animation/Animation.java,第1011‑1079行 public boolean getTransformation(long currentTime, Transformation outTransformation) { if (mStartTime == -1) { mStartTime = currentTime; } final long startOffset = getStartOffset(); final long duration = mDuration; float normalizedTime; if (duration != 0) { normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) / (float) duration; } else { // 时长为0时时间阶跃变化 normalizedTime = currentTime mStartTime ? 0.0f : 1.0f; } final boolean expired = normalizedTime = 1.0f || isCanceled(); mMore = !expired; if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); if ((normalizedTime = 0.0f || mFillBefore) (normalizedTime = 1.0f || mFillAfter)) { if (!mStarted) { fireAnimationStart(); mStarted = true; ... } if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); if (mCycleFlip) { normalizedTime = 1.0f - normalizedTime; } getTransformationAt(normalizedTime, outTransformation); } if (expired) { if (mRepeatCount == mRepeated || isCanceled()) { if (!mEnded) { mEnded = true; guard.close(); fireAnimationEnd(); } } else { if (mRepeatCount 0) { mRepeated++; } if (mRepeatMode == REVERSE) { mCycleFlip = !mCycleFlip; } mStartTime = -1; mMore = true; fireAnimationRepeat(); } } ... return mMore; }算法步骤:起始时间初始化:第一次调用将 mStartTime 置为 currentTime,实现 START_ON_FIRST_FRAME。归一化时间计算:normalizedTime = (currentTime‑startTime‑offset)/duration,得到单次周期进度 [0,1]。过期判断:normalizedTime =1.0 代表当前周期结束。Fill 钳位:mFillEnabled 开启时,将时间限制在 [0,1],防止外推。周期翻转:REVERSE 模式每次重复切换 mCycleFlip,为 true 时时间取反:1.0‑normalizedTime。应用变换:getTransformationAt () 执行插值并调用子类 applyTransformation ()。重复处理:动画过期但未耗尽重复次数,重置 mStartTime 为‑1,mMore 置 true,下一帧继续运行。14.2.11 resolveSize:数值类型解析 ¶resolveSize ()(1185 行)将动画数值依据类型转为像素:// Animation.java,第1185‑1196行 protected float resolveSize(int type, float value, int size, int parentSize) { switch (type) { case ABSOLUTE: return value; case RELATIVE_TO_SELF: return size * value; case RELATIVE_TO_PARENT: return parentSize * value; default: return value; } }支持 XML 写法如android:fromXDelta="50%"(相对自身)、android:fromXDelta="50%p"(相对父容器)。14.2.12 窗口管理器中的视图动画窗口管理器内部也使用视图动画实现遗留窗口转场。WindowAnimationSpec 对 View 动画做封装,作用对象改为 SurfaceControl。动画 Transformation 矩阵转换为 SurfaceControl.Transaction 操作(setPosition、setMatrix、setAlpha)。14.2.13 插值器原生桥接所有内置插值器实现 NativeInterpolator,提供createNativeInterpolator()返回原生句柄。HWUI 使用该句柄,在 RenderThread 运行相同插值曲线,避免每一帧跨 JNI 调用。// AccelerateDecelerateInterpolator.java,第43‑47行 /** @hide */ @Override public long createNativeInterpolator() { return NativeInterpolatorFactory.createAccelerateDecelerateInterpolator(); }frameworks/base/libs/hwui/Interpolator.cpp中原生实现与 Java 公式完全一致,保证 UI 线程与 RenderThread 动画视觉效果统一。14.2.14 视图动画文件总览 ¶表格文件行数用途Animation.java1363抽象基类AnimationSet.java553并发动画组AnimationUtils.java~400加载工具、currentAnimationTimeMillisTransformation.java~220矩阵 + 透明度容器AlphaAnimation.java89透明度动画TranslateAnimation.java241位移动画RotateAnimation.java183旋转动画ScaleAnimation.java289缩放动画ClipRectAnimation.java~80裁剪矩形动画ExtendAnimation.java~60边缘扩展动画TranslateXAnimation.java~40X 轴平移(优化)TranslateYAnimation.java~40Y 轴平移(优化)PathInterpolator.java245贝塞尔 / 路径插值AccelerateDecelerateInterpolator.java48默认余弦缓动AccelerateInterpolator.java~55幂曲线加速DecelerateInterpolator.java~55幂曲线减速LinearInterpolator.java~35线性BounceInterpolator.java~50末尾弹跳OvershootInterpolator.java~60三次过冲AnticipateInterpolator.java~55运动前蓄力AnticipateOvershootInterpolator.java~70蓄力 + 过冲组合CycleInterpolator.java~45正弦周期BackGestureInterpolator.java~60返回手势曲线BaseInterpolator.java~30插值器抽象基类Interpolator.java~10继承 TimeInterpolator 的接口LayoutAnimationController.java~350子 View 错峰动画GridLayoutAnimationController.java~200网格错峰动画14.3 属性动画14.3.1 概述Android3.0(API11)引入属性动画,是 Android 现代动画主力。它修改任意 Java 对象真实属性,不只限于 View。当执行 View.setTranslationX 动画时,属性真实发生改变,点击检测、布局、无障碍均跟随动画状态。源码目录:frameworks/base/core/java/android/animation/(31 个文件,~13400 行)14.3.2 核心类继承体系14.3.3 ValueAnimator 深度解析ValueAnimator.java(1776 行)是属性动画的引擎。关键字段(96‑279 行)// frameworks/base/core/java/android/animation/ValueAnimator.java private static float sDurationScale = 1.0f; // 系统全局缩放系数(96行) long mStartTime = -1; // 第一帧时间(113行) float mSeekFraction = -1; // 跳转播放位置(119行) private long mDuration = 300; // 默认300ms(202行) private int mRepeatCount = 0; // 默认播放一次(211行) private int mRepeatMode = RESTART; // RESTART 或 REVERSE(218行) private TimeInterpolator mInterpolator = sDefaultInterpolator; //(237行) PropertyValuesHolder[] mValues; // 被动画的属性数组(247行) HashMapString, PropertyValuesHolder mValuesMap; // 属性名‑PVH查找表注意:Android17 移除老版本mStartTimeCommitted“卡顿补偿” 标记;每个动画器用于修正起始时间的 commit 回调已删除(见 §14.3.12)。时长缩放:全局静态sDurationScale会乘以所有动画时长。开发者选项 “动画器时长缩放” 修改该值。等于 0 时areAnimatorsEnabled()返回 false。// ValueAnimator.java,394‑396行 public static boolean areAnimatorsEnabled() { return !(sDurationScale == 0); }工厂方法(417‑515 行)工厂方法求值器说明ofInt(int...)IntEvaluator整数区间ofFloat(float...)FloatEvaluator浮点数区间ofArgb(int...)ArgbEvaluatorsRGB 颜色插值ofObject(TypeEvaluator, Object...)自定义任意类型ofPropertyValuesHolder(PVH...)按每个 Holder多属性同时动画14.3.4 动画帧循环调用 start (),ValueAnimator 将自身注册到 AnimationHandler,作为 AnimationFrameCallback。Handler 调度 Choreographer 帧回调。每次 VSYNC 到来:animateBasedOnTime () 核心时序逻辑(简化):计算currentIterationFraction = (currentTime‑startTime)/duration处理重复:除以总迭代次数得到 overallFractionREVERSE 模式:奇数迭代翻转 fraction调用 animateValue (fraction),应用插值器14.3.5 ObjectAnimatorObjectAnimator(1004 行)继承 ValueAnimator,将动画数值直接设置给目标对象。两种解析目标属性的方式:属性名字符串:反射查找 setFoo () /getFoo ();float、int 返回类型存在优化 JNI 路径。Property 对象:使用 PropertyT,V 抽象,完全避开反射。// frameworks/base/core/java/android/animation/ObjectAnimator.java,69‑80行 public final class ObjectAnimator extends ValueAnimator { private Object mTarget; private String mPropertyName; private Property mProperty; private boolean mAutoCancel = false; ... }常用工厂:ObjectAnimator.ofFloat(view, "translationX", 0f, 100f) ObjectAnimator.ofFloat(view, View.TRANSLATION_X, 0f, 100f) // 推荐,无反射 ObjectAnimator.ofArgb(view, "backgroundColor", Color.RED, Color.BLUE)14.3.6 PropertyValuesHolderPropertyValuesHolder(1729 行)封装单个被动画属性:属性名 / Property 引用、setter/getter、关键帧集合、类型求值器。// frameworks/base/core/java/android/animation/PropertyValuesHolder.java,38‑78行 public class PropertyValuesHolder implements Cloneable { String mPropertyName; protected Property mProperty; Method mSetter = null; private Method mGetter = null; Class mValueType; Keyframes mKeyframes = null; ... }内部维护每个 Class 的 setter/getter 静态缓存,避免重复反射:// PropertyValuesHolder.java,92‑97行 private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class, Double.class, Integer.class}; private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class, Float.class, Double.class};14.3.7 Keyframes 与 TypeEvaluatorsKeyframe 定义某个进度点(0.0‑1.0)对应的数值。KeyframeSet 保存有序 Keyframe 集合,在相邻关键帧之间插值。内置求值器:求值器运算IntEvaluatorstartValue + (int)(fraction * (endValue‑startValue))FloatEvaluatorstartValue + fraction * (endValue‑startValue)ArgbEvaluatorsRGB 色彩空间按通道插值PointFEvaluatorPointF 的 x、y 独立插值RectEvaluatorRect left/top/right/bottom 插值IntArrayEvaluatorint 数组逐元素插值FloatArrayEvaluatorfloat 数组逐元素插值14.3.8 AnimatorSet 与依赖图AnimatorSet(2280 行)用内部 Node 结构,把多个 Animator 组织成一张依赖关系图。Builder API 构建依赖链:AnimatorSet set = new AnimatorSet(); set.play(fadeIn).before(moveRight); set.play(fadeIn).before(scaleUp); set.play(moveRight).before(colorChange); set.play(scaleUp).before(colorChange);内部维护按时间排序的 AnimationEvent 列表。每一帧,处理时间已到达的事件,启动或结束子动画器。14.3.9 AnimationHandler 与后台暂停AnimationHandler(515 行)管理线程内动画循环。关键机制 ——后台暂停(271‑287 行):当进程全部窗口切后台,AnimationHandler 暂停所有无限时长动画,节省 CPU。通过 mAnimatorRequestors 跟踪可见状态。// frameworks/base/core/java/android/animation/AnimationHandler.java,271‑287行 private Choreographer.FrameCallback mPauser = frameTimeNanos - { if (mAnimatorRequestors.size() 0) { return; // 调度之后有组件重新启用动画 } for (int i = 0; i mAnimationCallbacks.size(); ++i) { AnimationFrameCallback callback = mAnimationC