什么是过度绘制
过度绘制:GPU的绘制过程就和刷墙一样,一层一层的
进行,16ms刷一次,这样就会造成图层覆盖的现象,即无用的图层被绘制在底层,造成不必要的浪费。
发现问题
GPU过度绘制的的集中情况:
- 1、布局层次太深,重叠性太强,用户看不到的区域GPU也会渲染,导致耗时增加。
- 2、自定义控件中 onDraw 方法做了过多重复绘制
找到问题
1、使用Android手机自带的查看过度绘制的工具
2、Hierarchy Viewer
我们可以借助一些工具来查看我们的布局层级。Hv工具,现在HV在SDK里找不到了,google已经把它隐藏起来。并且hv有只能在开发版手机或模拟器运行的限制。目前的HV工具已经处于废弃状态,试了很多次用不了。我们可以前往
http://mirrors.zzu.edu.cn/android/repository/
下载旧版本的tools
下载完后解压,双击打开HV工具
或者在AndroidStudio中的HV工具
我们看到视图中几乎所有节点都有三个点,颜色也各不相同
这三个点也是代表着View的Measure, Layout和Draw。
不同颜色意味着不同的速度:
- 绿: 表示该View的此项性能比该View
Tree中超过50%的View都要快;例如,代表Measure的是绿点,意味着这个视图的测量时间快于树中的视图对象的50%; - 黄: 表示该View的此项性能比该View Tree中超过50%的View都要慢;
红: 表示该View的此项性能是View Tree中最慢的;
3、Layout Inspactor
LI可以帮助我们在程序运行的时候分析布局文件(ui绘制时间与嵌套层级),从而找到性能瓶颈。Hierarchy Viewer已经被置为deprecated的了,取而代之的是Layout Inspactor,也可以说LI就是新版的HV。 并且Li没有hv只能在开发版手机或模拟器运行的限制。
4、Lint
优化布局是一项非常繁琐复杂的工作,所以我们平时在开发中一定要注意。
除了使用HV和LI两种工具之外,我们还可以使用Lint检查,让Lint给出存在问题的地方来修改(activity_main)。
解决问题
1、Include、merge
在开发中我们经常会需要在不同地方放入相同的布局,有些布局可以被复用。这种情况可以创建一份单独的xml来定义这个可被复用的layout。比如需要自己定义ToolBar/ActionBar。那么需要设置theme为:
最后在Activity中
setSupportActionBar((Toolbar) findViewById(R.id.toolBar));
基本上如果使用了Toolbar那么我们app的每个界面都会需要,这里可以根据情况来,将Toolbar整体写入到一个单独的xml中(Toolbar中内容不会改变)或者将Toolbar内容写到单独xml中(Toolbar中内容会改变)。为了能够重用代码,在其他页面中直接include标签就可以了。
merge标签的作用在于不会增加层级会被系统自动忽略。
2、ViewStub
- INVISIBLE:view在layout布局文件中会占用位置,但是view为不可见,该view还是会创建对象,会被初始化,会占用资源;
- GONE:view在layout布局文件中不占用位置,但是该view还是会创建对象,会被初始化,会占用资源;
- ViewStub:不可见,不用占用资源,只有设置viewstub为visible、invisible或者调用其inflater()方法时,其对应的布局文件才会被初始化。局限是viewstub的引用对象需要是一个布局layout文件,如果要是单个的view的话,viewstub就不合适了。
其中layout和include一样都表示需要加载的xml布局文件。
inflatedId是设置—在这个布局被加载后的id。
也就是说在ViewStub被加载后,我们再使用edit_stub这个id就不能找到ViewStub了。而应该使用edit_layer来查找这一个视图。
3、ViewGroup里面有很深的子控件层级, 或者有不必要的子控件,这样的布局文件会使得程序变卡,性能降低。
首先布局文件我们需要牢记:
- 1、 布局层级越少越好
- 2、 布局中控件数越少越好
能肯定的是需要测量与绘制的控件越少,耗时越低,性能越好。而层级越少意味着在绘制控件的时候需要参考的父/子控件越少。
总结
性能优化其实不仅仅是一种技术,而是一种思想,你只听过它的高大上,却不知道它其实就是各个细节处的深入研究和处理,就像挤牙膏一样。
- 1、布局里面是否有背景
- 2、是否可以删除多余的布局
- 3、自定义View是否进行了裁剪
- 4、布局是否扁平化