Window Animator

609 阅读6分钟

基于Android R版本

DrawState

我们之前在分析WMS窗口相关流程的时候,按照DrawState的阶段进行了分析;

WMS窗口创建架构.png

当Activity.onResume()被调用之后,客户端会与WMS进行通信将我们的布局显示在屏幕上;

在这个过程中,涉及到一个概念:mDrawState

namevaluedesc
NO_SURFACE0mDrawState在定义的时候,默认 = 0,即NO_SURFACE 当一个窗口刚刚被WMS执行addWindow()方法创建的时候,WindowStateAnimator在WindowState的构造函数中一起被创建,在relayoutWindow之前,窗口是没有Surface的,所以不可能被显示出来,此时状态就是NO_SURFACE;
DRAW_PENDING1客户端调用了relayoutWindow(),这个时候通过WindowManagerServcice的createSurfaceControl()创建了SurfaceControl,然后为窗口创建了一块空白的Surface,此时需要客户端在Surface上作画,但由于Surface为空白状态,所以还是不能显示出;
COMMIT_DRAW_PENDING2在获取到要绘制的Surface时,ViewRootImpl就通过Canvas在Surface上进行绘制,绘制完成之后会调用Session的finishDrawing()方法,调用到WMS的finishDrawingWindow()方法;
READY_TO_SHOW3在WMS内部的findDrawingWindow()在设置完状态后,接着执行了mWindowPlacerLocked.requestTraversal()来请求刷新窗口,跟着调用关系,最终会调用到DIsplayContent的applySurfaceChangesTransaction()方法
HAS_DRAWN4最后阶段会执行WindowState的performShowLocked()显示画面

在WMS中,我们可以通过一个状态值mDrawState来划分几个阶段:

NO_SURFACE:在创建WindowState后的默认状态,表示当前窗口还创没有执行relayout()方法创建Surface;

  • 客户端通知WMS创建一个窗口,并添加到WindowToken,即addToDisplayAsUser阶段;
  • 客户端通知WMS创建Surface,并计算窗口尺寸大小,即relayoutWindow阶段;

DRAW_PENDING:执行relayout()方法后,创建完成Surface后的状态,表示等待绘制;

  • 客户端获取到WMS计算的窗口大小后,进一步测量该窗口下View的宽度和高度,即performMeasure阶段;
  • 客户端确定该窗口下View的尺寸和位置,即performLayout阶段;
  • 确定好View的尺寸大小位置之后,便对View进行绘制,即performDraw阶段;

COMMIT_DRAW_PENDING:窗口Surface上完成绘制后的状态,执行WindowStateAnimator#finishDrawingLocked()方法设置,表示已经完成绘制,等待下次刷帧进行提交;

  • 通知WMS,客户端已经完成绘制,即reportDrawFinished阶段;

READY_TO_SHOW:表示窗口已经绘制完成并且完成提交,此时如果该窗口的兄弟窗口全部完成绘制且满足显示要求,则直接进行HAS_DRAWN的转变完成显示,否则等待其他兄弟窗口完成绘制后,再进行HAS_DRAWN转变;

  • WMS接收到客户端通知后,紧接着向WMS Animator发送通知,即commitFinishDrawingLocked阶段;

HAS_DRAWN:表示该窗口正式显示;

  • WMS进行系统窗口的状态刷新以及动画处理,并最终将Surface显示出来,即performShowLocked阶段;

Leash

SurfaceAnimator的startAnimation方法中创建Leash,可以通过SurfaceAnimator的类注释了解Leash

这个类可以针对那种存在多个child surface的对象进行动画,在执行动画的过程中会创建一个没有Buffer的Surface---“Leash”,将所有child surface绑定到leash上,leash同时也会绑定到原先这些child surface绑定的位置;

然后我们将leash给到AnimationAdapter去执行动画,执行动画结束后会将所有child surface重新绑定到原先的父节点上;

其作用主要是用于解绑WindowAnimator的animate函数

之前要持锁是历史原因,而且动画过程中会改变window的属性,所以必须持锁,Android P之后动画不在改变window属性,直接通过transaction把动画修改传递到surfaceflinger;

leash是wms新的层级结构的一层,特意设计用来做窗口动画的,相当于在不改变window的属性的前提下,直接改leash的transaction属性就能实现窗口动画,相当于动画和window隔离,类似于设计模式里面的职责单一模式,leash就是窗口动画的单一功能职责;

Window Animation 启动入口

我们知道,当DrawState = HAS_DRAWN阶段的时候,将进行系统窗口的状态刷新以及动画处理;

applySurfaceChangesTransaction.png

在DisplayContent的applySurfaceChangesTransaction()函数中,会调用每个窗口的WindowStateAnimator#commitFinishDrawingLocked(),这个函数是用于处理绘制状态为COMMIT_DRAW_PENDINGREADY_TO_SHOW的窗口,因为窗口到了这两个状态下才能做窗口动画;

随后会调用WindowState#performShowLocked,并调用WindowStateAnimator的applyEnterAnimationLocked,最后把绘制状态改为HAS_DRAWN

当进入WindowStateAnimator的applyEnterAnimationLocked之后,后面走的是Surface动画的统一流程;

当窗口的状态变成HAS_DRAW后,会在prepareSurface中被show出来,这样子窗口已经变为可见,并开始做动画;

applyEnterAnimationLocked

我们在上述的分析中知道,applyEnterAnimationLocked()是用于加载窗口动画;

applyEnterAnimationLocked.png

这个过程中,我们可以看到,大致是执行了两件事件:

  • 动画资源的加载;
  • 开始窗口动画绘制;

我们在分析applySurfaceChangesTransaction()方法的过程中,我们描述了applyEnterAnimationLocked()方法只是用于加载动画资源,但是在实际的代码分析中,我们可以发现,动画的加载和动画的执行都是在该方法中被执行的;

applyEnterAnimationLocked # startAnimation

startAnimation_.png

这个startAnimation是从applyEnterAnimationLocked()方法中调用过来的,当动画资源加载完成之后,会调用该方法;

这个过程中主要执行了3件事:

  • 根据加载出来的TransitionAnimation创建对应的LocalAnimationAdapter()实例;
  • 为当前的WindowState的SurfaceControl创建对应的leash layer,该leash也同样对应一个SurfaceControl,WindowState的SurfaceControl会重新挂载到leash的SurfaceControl下,直到WindowState的动画结束之后,WindowState的SurfaceControl才会重新挂载到之前的父节点上,同时leash layer也会被移除;
  • 向Choreographer注册FrameCallback,其对应的CallbackType = CALLBACK_ANIMATION,代表了该Callback是用于处理动画事务的,监听Vsync信号的上报;
FrameCallback receiver

我们知道,在startAnimation()方法中向Choreographer注册了FrameCallback,当Choreographer接收到Vsync的信号之后,会调用该Callback;

doFrame_startAnimation.png

最终又从Choreographer中回调回了SurfaceAnimationRunner中,在SurfaceAnimationRunner中进行了ValueAnimator的配置,这个过程我们就不具体分析了,我们直接管制Update Listener和Animator Listener;

AnimatorUpdateListener

这一块的回调也是从Choreographer中回调回来的,我们知道ValueAnimator的工作机制也是基于Choreographer;

我们需要知道,ValueAnimator本身也涉及一个FrameCallback;

Window_Animation_Update.png

在该过程中,主要执行了两件事件:

  • applyTransformation:对FrameTransaction事务进行参数配置;
  • scheduleApplyTransaction:本次又向Choreographer注册了一个Callback,不过这一次的CallbackType = Runnable;
AnimatorUpdateListener # Runnable

这个Runnable的回调就是在scheduleApplyTransaction()方法中传入的Runnable Callback;

doFrame_Runnable.png

在这个过程中,我们将FrameTransaction中的配置进行了提交,发送给了SurfaceFlinger进行了绘制;

这里我们需要注意的是:FrameTransaction的配置和FrameTransaction的提交不是在同一帧过程中执行了,例如FrameTransaction的配置在第一帧的时候配置,但是会在第二帧的时候,才会将第一帧的FrameTransaction的配置提交到SurfaceFlinger中,会有一帧的延迟;

AnimatorListener end

当Animator Update结束之后,会执行Animator的end操作;

Window_Animation_end.png

这个过程比较简单,通过层层的Runnable注入回调回WindowState,通知Animator窗口动画绘制已经结束;

scheduleAnimationLocked

我们知道,applyEnterAnimationLocked()方法是在READY_TO_SHOW阶段执行的,其核心业务就是加载动画资源和绘制窗口动画

绘制窗口动画是依赖于Choreographer和Vsync机制的运行,即窗口动画也是一帧一帧进行绘制的,并不是将其全部绘制完成之后,才进行显示的;

scheduleAnimationLocked.png

scheduleAnimationLocked_doFrame.png