每次去面试都会被问到性能优化方面的问题,一直没有总结过,每次回答都是磕磕绊绊,趁此机会做一次总结,为下次面试做好准备吧。
- Debug GPU Overdraw(调试GPU过度渲染)
我们可以通过调试工具来检测Overdraw:设置——开发者选项——调试GPU过度绘制——显示过度绘制区域。
蓝色 – 1次过度绘制 – 这部分的像素点在屏幕上绘制了两次。
绿色 – 2次过度绘制 – 这部分的像素点在屏幕上绘制了三次。
粉色 – 3次过度绘制 – 这部分的像素点在屏幕上绘制了四次。
红色 – 4次过度绘制 – 这部分的像素点在屏幕上绘制了五次。
尽量保证页面上只有尽量多的蓝色区域,否则,接下来我们就需要使用Hierarchy Viewer 来进一步分析布局,以便优化。
1.在Android Studio中通过
Tools>Android>Android Device Monitor
启动Android Device Monitor。注意:先运行APP再使用Android Device Monitor。如下图:
2.启动Android Device Monitor成功之后,在新的的窗口中点击切换视图图标,选择Hierarchy View,如下图:
![]()
3.Hierarchy Viewer的具体使用可以参考google的官方文档https://developer.android.com/studio/profile/hierarchy-viewer.html
4.出于安全考虑,Hierarchy Viewer不支持直接连接真机进行检测,连接真机时会报如下错误:
01:47:20 E/hierarchyviewer: Unable to get view server version from device e8ef8e7e 01:47:20
E/hierarchyviewer: Unable to get view server protocol version from device e8ef8e7e为了能够对真机使用,Android SDK开发团队提供了ViewServer开源库,项目地址https://github.com/romainguy/ViewServer,根据该项目的指导引入该库并配置后,就可以在对真机使用Hierarchy Viewer啦。
- Profile GPU Rendering(分析GPU渲染)
设置——开发者选项——GPU配置渲染(不同厂商中文翻译有区别)——以条的形式显示于屏幕。开启后如下图:
![]()
如我们所知,一帧的绘制时间如果超过16ms,就能实际的感受到视觉上的差异,就是我们平常说的卡顿。GPU呈现模式让我们以图形化的方式查看绘制每一帧的时间是否超过16ms,通过这种方式可以粗略的定位哪一部分操作比较卡顿。
如上图所示,图中每条竖线代表一帧,不同的颜色代表这一帧在绘制中的不同步骤,竖线的高度就是绘制一帧所花费的时间。上方的横线表示16ms,如果竖线的高度超过16ms,那么这一帧的绘制时间就超过了建议的时间范围,即会带来卡顿。我们可以查看是什么操作导致了竖线的高度飙升,以此进行初步的定位卡顿。
初步定位可能导致卡顿的操作后,如果要进行更详细的定位,那么,我们可以借助TraceView来帮忙。TraceView是Android Studio集成的一个性能优化工具,相信很多人都知道它,但是用到它的应该不多,它的使用比较复杂,应该说理解比较复杂。它主要用图形的形式展示代码的执行时间、次数及调用栈,以此来分析App运行效率。
使用TraceView,首先编译我们的程序,接着在Android Studio中打开Android Monitor,点击 Start Method Tracing,如下图:
![]()
然后操作我们的app,打开页面点击按钮啥的,最后再次点击Start Method Tracing就完成了一次tracing。完成
更详细的TraceView使用教程可以参考google官方文档
上面简单介绍了几种性能分析工具,接下来再简单说几个布局优化时常涉及到的点:
1、使用include
标签重用布局
2、使用include
标签重用布局时,常与merge
标签同用,用以减少布局嵌套
3、使用viewStub
标签,实现布局的延迟加载,类似网络异常提示这种只在特定情况下才需要加载的布局使用,不仅可以提高性能,也可以节省内存(初始化对象不被创建)
ViewStub viewStub = (ViewStub)view.findViewById(R.id.mask);
viewStub.inflate();
4、LinearLayout与RelativeLayout的选择
参考资料:RelativeLayout和LinearLayout性能比较相对布局和线性布局的性能比较
(1)RelativeLayout会让子View调用2次onMeasure,LinearLayout 在设置了weight属性时,也会让子View调用2次onMeasure
(2)RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
(3)在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。
(4)提高绘制性能的使用方式
根据上面源码的分析,RelativeLayout将对所有的子View进行两次measure,而LinearLayout在使用weight属性进行布局时也会对子View进行两次measure,如果他们位于整个View树的顶端时并可能进行多层的嵌套时,位于底层的View将会进行大量的measure操作,大大降低程序性能。因此,应尽量将RelativeLayout和LinearLayout置于View树的底层,并减少嵌套。
5、自定义控件时,注意在onDraw方法中,尽量避免执行大量操作。主要体现在两方面。
1.避免在onDraw中创建新的局部对象。因为onDraw方法可能会被频繁调用,这样就会在一瞬间产生大量的临时对象,占用过多内存还会导致系统更加频繁的GC,降低程序的执行效率。
2.View的绘制帧率保证60fps最好,即要求每帧的绘制时间不超过16ms,所以,避免在onDraw中执行耗时的任务,例如执行大量的循环操作。
6、想到再补充。