本文主要是介绍android 系统源码挖掘之Animator性能优化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
作者:zjw-swun
博客:https://juejin.im/user/58994f1d128fe1006cbfe0da
声明:本文由作者 zjw-swun 授权发布,未经原作者允许请勿转载
今天在看FragmentManager源码的时候看见了一段关于优化动画性能的代码,经过真机实测,发现确实达到了不错的性能优化效果,分享给大家
1. 优化前后效果对比图
前提: 手机为真机, 魅族MX5E, 系统 5.0( api 26的模拟器下看GPU 条形图不知道为什么优化代码反而不如不优化的,可能是没有硬件加速导致的吧)
优化前效果如下
优化后效果如下
经过对比发现,确实性能优化不少
2. 从android源码扣出来的优化动画的关键代码以及测试代码
我这边给出我扣出来的代码(kotlin版本)
1class AnimateOnHWLayerIfNeededListener(private var mView: View?) : Animator.AnimatorListener {
2 private var mShouldRunOnHWLayer = false
3
4
5 override fun onAnimationStart(animation: Animator) {
6 mShouldRunOnHWLayer = shouldRunOnHWLayer(mView, animation)
7 if (mShouldRunOnHWLayer) {
8 mView!!.setLayerType(View.LAYER_TYPE_HARDWARE, null)
9 }
10 }
11
12 override fun onAnimationEnd(animation: Animator) {
13 if (mShouldRunOnHWLayer) {
14 mView!!.setLayerType(View.LAYER_TYPE_NONE, null)
15 }
16 mView = null
17 animation.removeListener(this)
18 }
19
20 override fun onAnimationCancel(animation: Animator) {
21
22 }
23
24 override fun onAnimationRepeat(animation: Animator) {
25
26 }
27
28 fun shouldRunOnHWLayer(v: View?, anim: Animator?): Boolean {
29 return if (v == null || anim == null) {
30 false
31 } else v.layerType == View.LAYER_TYPE_NONE
32 && v.hasOverlappingRendering()
33 && modifiesAlpha(anim)
34 }
35
36
37 private fun modifiesAlpha(anim: Animator?): Boolean {
38 if (anim == null) {
39 return false
40 }
41 if (anim is ValueAnimator) {
42 val valueAnim = anim as ValueAnimator?
43 val values = valueAnim!!.values
44 for (i in values.indices) {
45 if ("alpha" == values[i].propertyName) {
46 return true
47 }
48 }
49 } else if (anim is AnimatorSet) {
50 val animList = anim.childAnimations
51 for (i in animList.indices) {
52 if (modifiesAlpha(animList[i])) {
53 return true
54 }
55 }
56 }
57 return false
58 }
59 }
java 版本如下
1static class AnimateOnHWLayerIfNeededListener implements Animator.AnimatorListener {
2 private boolean mShouldRunOnHWLayer = false;
3 private View mView;
4 public AnimateOnHWLayerIfNeededListener(final View v) {
5 if (v == null) {
6 return;
7 }
8 mView = v;
9 }
10
11 @Override
12 public void onAnimationStart(Animator animation) {
13 mShouldRunOnHWLayer = shouldRunOnHWLayer(mView, animation);
14 if (mShouldRunOnHWLayer) {
15 mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
16 }
17 }
18
19 @Override
20 public void onAnimationEnd(Animator animation) {
21 if (mShouldRunOnHWLayer) {
22 mView.setLayerType(View.LAYER_TYPE_NONE, null);
23 }
24 mView = null;
25 animation.removeListener(this);
26 }
27
28 @Override
29 public void onAnimationCancel(Animator animation) {
30
31 }
32
33 @Override
34 public void onAnimationRepeat(Animator animation) {
35
36 }
37
38 static boolean shouldRunOnHWLayer(View v, Animator anim) {
39 if (v == null || anim == null) {
40 return false;
41 }
42 return v.getLayerType() == View.LAYER_TYPE_NONE
43 && v.hasOverlappingRendering()
44 && modifiesAlpha(anim);
45 }
46
47 static boolean modifiesAlpha(Animator anim) {
48 if (anim == null) {
49 return false;
50 }
51 if (anim instanceof ValueAnimator) {
52 ValueAnimator valueAnim = (ValueAnimator) anim;
53 PropertyValuesHolder[] values = valueAnim.getValues();
54 for (int i = 0; i < values.length; i++) {
55 if (("alpha").equals(values[i].getPropertyName())) {
56 return true;
57 }
58 }
59 } else if (anim instanceof AnimatorSet) {
60 List<Animator> animList = ((AnimatorSet) anim).getChildAnimations();
61 for (int i = 0; i < animList.size(); i++) {
62 if (modifiesAlpha(animList.get(i))) {
63 return true;
64 }
65 }
66 }
67 return false;
68 }
69 }
测试代码 xml如下 ,布局很简单5个宽高全屏幕的View,然后做alpha动画
重点就是alphaAnimation.addListener(AnimateOnHWLayerIfNeededListener(v))这句代码,就是用了FragmentManager源码中扣出来的动画优化代码。
3. 扩展总结
上述代码解决了alpha动画的优化,那么如果是scale,x,y移动动画呢,同理啦,就是把判断alpha的代码去掉就行了,核心其实就是动画开始前启用离屏缓冲,也就是mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);,然后动画结束的时候,关闭离屏缓冲,也就是mView.setLayerType(View.LAYER_TYPE_NONE, null);,很多朋友搞不清楚,硬件加速和View.LAYER_TYPE_HARDWARE的关系,我这里说一下,android 4.0以后所有页面默认全部开启硬件加速,View树无特殊情况,LayerType是View.LAYER_TYPE_NONE,LAYER_TYPE_HARDWARE这个叫做硬件层面的离屏缓冲(学过java swing的同学应该知道一个叫双缓冲的东西,LAYER_TYPE_HARDWARE就是使用了硬件做双缓冲),LAYER_TYPE_HARDWARE和硬件加速关系是当硬件加速开启的时候才能使用硬件离屏缓冲(硬件双缓冲)LAYER_TYPE_HARDWARE,而如果你指定View的LayerType为LAYER_TYPE_SOFTWARE 这个叫做软离屏缓冲(用内存做双缓冲),使用了LAYER_TYPE_SOFTWARE等于主动放弃了硬件加速,那为什么要主动放弃能够提高渲染性能的硬件加速呢?因为有一些canvas的操作不支持硬件加速,这些不支持的点你可以去android开发者文档官网找到。
在说一下,上述思路解决了属性(alpha,scale,x,y)动画优化,如果要使用动画改变控件的宽高的时候如何优化呢?很明显会卡死,原理就是会导致在极端的时间了全局的requestLayout 重新measure layout draw整个视图树,优化方法可以看到我之前的基于recyclerView add子view思想动态改变控件宽高 优化的文章,链接为:https://www.imooc.com/article/21993
好了,分享到此结束。喜欢就点个推荐吧。
征稿:科技互联网,技术类文章
投稿方式:
发送文章链接地址到邮箱:748778890@qq.com
注明“投稿”,收到会回复哟
这篇关于android 系统源码挖掘之Animator性能优化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!