Android应用程序UI硬件加速渲染的动画执行过程分析
通常我们说一个系统不如另一个系统流畅,说的就是前者动画显示不如后者流畅,因此动画显示流畅程度是衡量一个系统流畅性的关键指标。为什么这样说呢?这是因为流畅的动画显示需要60fps的UI刷新速度,然而这却不是一个容易达到的速度。Android 5.0通过引入Render Thread尽最大努力提升动画显示流畅性。本文就分析Render Thread显示动画的过程,以便了解它是如何提高动画显示流畅性的。
在前面一文中,我们提到了Render Thread对动画显示的两个优化。第一个优化是在动画显示期间,临时将动画的目标View的Layer Type设置为LAYER_TYPE_HARDWARE,这样就可以使得目标View以Open GL里面的Frame Buffer Object(FBO)进行渲染。这种优化的效果就如Render Thread直接以Open GL里面的Texture来渲染TextureView一样。第二个优化是在Main Thread不需要参与动画的显示过程时,动画就会被注册到Render Thread中,这样动画的计算和显示过程就完全由Render Thread来负责。这种优化带来的好处就是在动画显示期间,Main Thread可以去处理其它的用户输入,而且动画的显示也会更加流畅。团建活动策划
上面描述的两种动画优化涉及到的Main Thread和Render Thread的交互过程如图1所示:
接下来,我们就通过代码分析上述的两种动画显示优化过程。
我们通过调用View类的成员函数animate可以获得一个ViewPropertyAnimator对象,如下所示:
[java] view plain copy
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
......
public ViewPropertyAnimator animate() {
if (mAnimator == null) {
mAnimator = new ViewPropertyAnimator(this);
}
return mAnimator;
}
大学几月开学
......
}
这个函数定义在文件frameworks/ba/core/java/android/view/View.java中。
有了这个ViewPropertyAnimator对象之后,就可以调用它的成员函数withLayer将它关联的View的Layer Type设置为LAYER_TYPE_HARDWARE,如下所示:
[java] view plain copy
public class ViewPropertyAnimator {
......
如何种葱 public ViewPropertyAnimator withLayer() {
mPendingSetupAction= new Runnable() {
@Override
public void run() {
mView.tLayerType(View.LAYER_TYPE_HARDWARE, null);
if (mView.isAttachedToWindow()) {
mView.buildLayer();
}
}
};
final int currentLayerType = LayerType();
mPendingCleanupAction = new Runnable() {
@Override
public void run() {
mView.tLayerType(currentLayerType, null);
}
};
......
return this;
}
......
怎么清洗打印机喷头}
这个函数定义在文件frameworks/ba/core/java/android/view/ViewPropertyAnimator.java中。
ViewPropertyAnimator类的成员函数withLayer创建了两个Runnable,分别保存在成员变量mPendingSetupAction和mPendingCleanupAction中。其中,成员变量mPendingSetupAction指向的Runnable在动画开始显示之前执行,而成员变量mPendingCleanupAction指向的Runnable在动画结束显示之后执行。由此我们就可以看到:
1. 在动画开始显示之前,目标View的Layer Type会被设置为LAYER_TYPE_HARDWARE,并且它的成员函数buildLayer会被调用来创建一个Layer。
2. 在动画结束显示之后,目标View的Layer Type会被恢复为它之前的Layer Type。注意,这里调用目标View的成员函数getLayerType获得的是它的Layer Type未被设置为LAYER_TYPE_HARDWARE的Layer Type。
接下来我们就继续分析View类的成员函数buildLayer的实现,以便可以了解为一个View设置一个Layer的过程。
当兵体检 View类的成员函数buildLayer的实现如下所示:
[java] view plain copy
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
......
public void buildLayer() {
......
final AttachInfo attachInfo = mAttachInfo;
......
switch (mLayerType) {
ca LAYER_TYPE_HARDWARE:
updateDisplayListIfDirty();
if (attachInfo.mHardwareRenderer != null && mRenderNode.isValid()) {
attachInfo.mHardwareRenderer.buildLayer(mRenderNode);
}
break;
ca LAYER_TYPE_SOFTWARE:
buildDrawingCache(true);
break;
}
}
......
}
这个函数定义在文件frameworks/ba/core/Java/android/view/View.java中。
前面已经将当前正在处理的View的Layer Type设置为LAYER_TYPE_HARDWARE,因此View类的成员函数buildLayer首先是调用我们在前面一文中分析过的View类的另外一个成员函数updateDisplayListIfDirty更新它的Display List。更新完毕之后,再调用保存在成员变量mAttachInfo描述的一个AttachInfo对象的成员变量mHardwareRenderer指向的一个ThreadedRenderer对象的成员函数buildLayer为当前正在处理的View创建一个Layer。
从这里还可以看到,如果当前正在处理的View的Layer Type被设置为LAYER_TYPE_S
OFTWARE,即该View是以软件方式进行渲染的,那么就会调用另外一个成员函数buildDrawingCache将View上次绘制得到的UI缓存在一个Bitmap中,以便下次可以快速地绘制View动画的下一帧。View类的成员函数buildDrawingCache的实现,同样可以参考前面一文。
接下来我们主要关注为一个View创建一个Layer的过程,即ThreadedRenderer对象的成员函数buildLayer的实现,如下所示:
[java] view plain copy
public class ThreadedRenderer extends HardwareRenderer {
...... 进入bios
原电池反应
@Override
void buildLayer(RenderNode node) {
nBuildLayer(mNativeProxy, NativeDisplayList());