Android性能优化:绘制优化

6、二级绿-Animation

执行动画所需要花费的时间。越高表示使用了非官方动画工具或执行中有读写操作。

7、三级绿-Input Handling

系统处理输入事件所耗费的时间。

8、四级绿-Misc Time/Vsync Delay

主线程执行了太多任务,导致UI渲染跟不上vSync的信号而出现掉帧。

此外,可通过如下 adb命令将具体的渲染耗时输出到日志中来分析

adb shell dumpsys gfxinfo com..

复制代码

2、TraceView


它主要用来分析函数的调用过程,可以对Android的应用程序以及Framework层代码进行性能分析。

使用TraceView查看耗时,主要关注Calls + Recur Calls / Total和(该方法调用次数+递归次数)和Cpu Time / Call(该方法耗时)这两个值,然后优化这些方法的逻辑和调用次数,减少耗时

注意

RealTime(实际时长)的实际执行时间要比CPU Time要长,因为它包括了CPU的上下文切换、阻塞、GC等时间消耗。

3、Systrace UI性能分析


Systrace是Android 4.1及以上版本提供的性能数据采样和分析工具,它的主要作用可以归结为如下两点:

  • 1、收集Android关键子系统(如surfaceflinger、WindowManagerService等Framework部分关键模块、服务、View系统等)的运行信息,这样可以更直观地分析系统瓶颈,改进性能

  • 2、跟踪系统的I/0操作、内核工作队列、CPU负载等,在UI显示性能分析上提供很好的数据,特别是在动画播放不流畅、渲染卡顿等问题上

1、Systrace使用方法

使用事项如下:

  • 支持4.1版本及以上。

  • 4.3以前的系统版本需要打开Setting>Developer options>Monitoring>Enable traces。

一般我们使用命令行来得到输出的html表单,在4.3版本及以上可以省略设置跟踪类别标签来获取默认值。命令如下:

cd android-sdk/platform-tools/systrace

python systrace.py --time=10 -o mynewtrace.html sched gfx view wm

复制代码

其中,常用的几个参数命令如下:

  • -o :保存的文件名。

  • -t N, --time=N:多少秒内的数据,默认为5s,以当前时间点往后倒N秒时间。

其余标签用法请参见此处

此外,我们可以使用代码插桩的方式,在Android 4.3及以上版本可以使用Trace类的Trace.beginSection()与Trace.endSection()方法来进行追踪。其中需要注意:

  • 1、保证beginSection和endSection的调用次数要匹配。

  • 2、Trace的begin与end必须在同一线程中执行。

2、分析Systrace报告

使用Chrome打开文件后,其中和UI绘制关系最密切的是Alerts和Frame两个数据:

  • Alerts:标记了性能有问题的点,单击该点可以查看详细信息,右侧的Alerts框还可以看到每个类型的Alerts的数量。

  • Frame:每个应用都有一行专门显示frame,绘制正常时每一帧就显示为一个绿色的圆圈。当显示为黄色或者红色时,则表明它的渲染时间超过了16.6ms

最后,这里再列出在Systrace便于操作的快捷键:

  • W:放大

  • S:缩小

  • A:左移

  • D:右移

三、布局优化方式

========================================================================

1、减少层级


  • 合理使用RelativeLayout和LinearLayout。

  • 合理使用Merge。

合理使用RelativeLayout和LinearLayout

RelativeLayout也存在性能低的问题,原因是RelativeLayout会对子View做两次测量。但如果在LinearLayout中有weight属性,也需要进行两次测量,但是因为没有更多的依赖关系,所以仍然会比RelativeLayout的效率高。

注意

由于Android的碎片化程度很高,所以使用RelativeLayout能使构建的布局适应性更强。

合理使用Merge

merge的原理:在Android布局的源码中,如果是Merge标签,那么直接将其中的子元素添加到Merge标签Parent中。

注意
  • 1、Merge只能用在布局XML文件的根元素。

  • 2、使用merge来加载一个布局时,必须指定一个ViewGroup作为其父元素,并且要设置加载的attachToRoot参数为true。

  • 3、不能在ViewStub中使用Merge标签。原因就是ViewStub的inflate方法中根本没有attachToRoot的设置。

2、提高显示速度


ViewStub是一个轻量级的View,它是一个看不见的,并且不占布局位置,占用资源非常小的视图对象。可以为ViewStub指定一个布局,加载布局时,只有ViewStub会被初始化,然后当ViewStub被设置为可见时,或是调用了ViewStub.inflate()时,ViewStub所指向的布局才会被加载和实例化,然后ViewStub的布局属性都会传给它指向的布局

注意:

  • 1、ViewStub只能加载一次,之后ViewStub对象会被置为空。所以它不适用于需要按需显示隐藏的情况。

  • 2、ViewStub只能用来加载一个布局文件,而不是某个具体的View。

  • 3、ViewStub中不能嵌套Merge标签。

3、布局复用


Android的布局复用可以通过 include 标签来实现。

4、小结


最后,下面列出了我平常做布局优化时的一些小技巧:

  • 使用标签加载一些不常用的布局。

  • 尽可能少用wrap_content,wrap_content会增加布局measure时的计算成本,已知宽高为固定值时,不用wrap_content。

  • 使用TextView替换RL、LL。

  • 使用低端机进行优化,以发现性能瓶颈。

  • 使用TextView的行间距替换多行文本:lineSpacingExtra/lineSpacingMultiplier。

  • 使用Spannable/Html.fromHtml替换多种不同规格文字。

  • 尽可能使用LinearLayout自带的分割线。

  • 使用Space添加间距。

  • 多利用lint + alibaba规约修复问题点。

  • 嵌套层级过多可以考虑使用约束布局。

四、避免过度绘制

========================================================================

导致过度绘制的主要原因一般有如下两点:

  • XML布局:控件有重叠且都有设置背景。

  • View自绘:View.OnDraw里面同一个区域被绘制多次。

1、过度绘制检测工具


打开手机开发者选项中的Show GPU Overdraw选项,会有不同的颜色来表示过度绘制次数,依次是无、蓝、绿、淡红、深红,分别对应0-4次过度绘制。

2、如何避免过度绘制


1、布局上的优化

  • 移除XML中非必需的背景,或根据条件设置。

  • 有选择性地移除窗口背景:getWindow().setBackgroundDrawable(null)。

  • 按需显示占位背景图片。

比如:在获取Avatar的图像之后,把ImageView的Background设置为Transparent,只有当图像没有获取到时,才设置对应的Background占位图片。

2、自定义View优化

通过canvas.clipRect()来帮助系统识别那些可见的区域。这个方法可以指定一块矩形区域,只有在这个区域内才会被绘制。并且,它还可以节约CPU和GPU资源,在clipRect区域之外的绘制指令都不会被执行。

在绘制一个单元之前,首先判断该单元的区域是否在Canvas的剪切域内。若不在,直接返回,避免CPU和GPU的计算和渲染工作。

五、合理的刷新机制

=========================================================================

1、减少刷新次数


  • 控制刷新频率

  • 避免没有必要的刷新

2、避免后台线程的影响


如通过监听ListView的onScrollStateChanged事件,在滚动时暂停图片下载线程工作,结束后再开始,可以提高ListView的滚动平滑度,RecyclerView同理。

3、缩小刷新区域


如自定义View一般采用invalidate方法刷新,可以使用以下重载方法指定要刷新的区域:

  • invalidate(Rect dirty);

  • invalidate(int left, int top, int right, int bottom);

六、提升动画性能

========================================================================

提升动画性能主要从以下三个纬度着手:

  • 1、流畅度:控制每一帧动画在16m内完成。

  • 2、内存:避免内存泄漏,减小内存开销。

  • 3、耗电:减小运算量,优化算法,减小CPU占用。

1、帧动画


消耗资源最多,效果最差,能不用就不用。

2、补间动画


使用补间动画实现导致View重绘非常频繁,更新DisplayList的次数过多,且有以下缺点:

  • 1、只能用于View对象。

  • 2、只有4种动画操作。

  • 3、只是改变View的显示效果,但是不会真正改变View的属性。

3、属性动画


相比于补间动画,属性动画重绘明显会少很多,应优先使用。

4、使用硬件加速


1、硬件加速原理

核心类:DisplayList,每一个View对应一个。

在打开硬件渲染后绘制View时,其中执行绘制的draw()方法会把所有绘制命令记录到一个新的显示列表(DisplayList),这个显示列表包含了输出的View层级的绘制代码,但并不是加入到显示列表就立刻执行,当这个ViewTree的DisplayList全都记录完毕后,由OpenGLRender负责将Root View中的DisplayList渲染到屏幕上。而invalidate()方法只是在显示列表中记录和更新显示层级,去标记不需要绘制的View

2、硬件加速控制级别

如果应用程序中只使用了标准View或者Drawable,就可以为整个系统打开硬件加速的全局设置。

3、在动画上使用硬件加速

此时,会使用硬件纹理操作对一个View进行动画绘制,如果不调用invalidate()方法,就可以减少对View自身频繁的重绘。同时Android 3.0的属性动画也减小了重绘,当View通过硬件层返回时,最终所有的层叠画面显示到屏幕,View的属性同时被处理好,因此只要设置这些属性,就可以明显提高绘制的效率,它们不需要View重绘,设置属性后,View会自动刷新。因此,属性动画中绘制的递归次数比补间动画少很多。

在Android 3.0前,使用View的绘制缓冲或Canvas.saveLayer()函数对离屏缓冲进行渲染。Android 3.0后则使用View.setLayerType(type, paint)方法代替,type可以为以下三种Layer类型之一:

  • LAYER_TYPE_NONE:普通渲染方式,不会返回一个离屏的缓冲,默认值。

  • LAYER_TYPE_HARDWARE:如果这个应用使用了硬件加速,这个View将会在硬件中渲染为硬件纹理。

  • LAYER_TYPE_SOFTWARE:此View通过软件渲染为一个Bitmap。

设计一个动画的流程如下:

1、将要执行动画的View的LayerType设置为LAYER_TYPE_HARDWARE。

2、计算动画View的属性等信息,更新View的属性。

3、若动画结束,将LayerType设置为NONE。

硬件加速需要注意的问题:

  • 在软件渲染时,可以使用重用Bitmap的方法来节省内存,但是如果开起来硬件加速,这个方案就不起作用。

  • 开启硬件加速的View在前台运行时,需要耗费额外的内存,加速的UI切换到后台时,产生的额外内存有可能不释放。

  • 当UI中存在过渡绘制时,硬件加速会比较容易发生问题。

七、卡顿监控方案与实现

===========================================================================

目前比较流行的方案都是利用了Looper中的Printer来实现监控。

1、监控原理


利用主线程的消息队列处理机制,通过自定义Printer,然后在Printer中获取到两次被调用的时间差,这个时间差就是执行时间。如果该时间超过设定的卡顿阈值(如1000ms)时,主线程卡顿发生,并抛出各种有用信息,供开发者分析。(此外,也可以在UI线程以外开启一个异步线程,定时向UI线程发送一个任务,并记下发送时间。任务的内容是将执行时间同步到发送线程,如果UI线程被阻塞,那么发送过去的任务不能被准时执行。但此方法会增加系统开销,不可取)

卡顿信息捕获

发生卡顿时需要捕获如下四类信息,以提高定位卡顿问题的效率与精度。

  • 1、基础信息:系统版本、机型、进程名、应用版本号、磁盘空间、UID等。

  • 2、耗时信息:卡顿开始和结束时间。

  • 3、CPU信息:CPU的信息、整体CPU使用率和本进程CPU使用率(可粗略判断是当前应用消耗CPU资源太多导致的卡顿,还是其他原因)等。

  • 4、堆栈信息。

注意

这里的信息建议抽样上报或者可以先将其保存到本地,在合适的时机以及达到一定的量时,再压缩上报到服务器,供开发者分析。具体监控代码实现可以参考BlockCanary开源项目的代码。

八、总结

====================================================================

至此,这里我们分析一下绘制优化应经历的几个过程:

  • 1、发现问题:除使用时感知的卡顿外,还应通过卡顿监控工具来发现整体的耗时情况,或打开开发者选项的一些辅助工具来发现问题。

  • 2、分析问题:可以使用Systrace和TraceView来分析耗时,使用Hierarhy Viewer来分析页面层级。

  • 3、寻求原因:深入探索导致问题的根本原因。

  • 4、解决问题。

应用之所以会出现卡顿,除了绘制方面的问题,还有一个影响因素就是内存,不合理地使用内存不仅会导致卡顿,还会对耗电和应用的稳定性造成很大影响。下一篇性能优化文章,笔者将对Android中的内存优化进行全面的讲解,若读者觉得哪里有写的不好的地方或有误的地方希望多多进行批评指正,愿我们共同进步和成长!

九、分享

====================================================================

整理了一份721页,包含性能优化所有知识点的pdf学习笔记,内容涵盖设计思想与代码质量优化、程序性能优化、开发效率优化、其中详细讲解了启动优化、布局优化、内存优化、屏幕适配、OOM问题等方面,并还包含很多大厂的项目实战案例解析。

目录

性能优化部分解析内容

总结

开发是面向对象。我们找工作应该更多是面向面试。哪怕进大厂真的只是去宁螺丝,但你要进去得先学会面试的时候造飞机不是么?

作者13年java转Android开发,在小厂待过,也去过华为,OPPO等,去年四月份进了阿里一直到现在。等大厂待过也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。

这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

相信它会给大家带来很多收获:

960页全网最全Android开发笔记

资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
面试的时候造飞机不是么?

作者13年java转Android开发,在小厂待过,也去过华为,OPPO等,去年四月份进了阿里一直到现在。等大厂待过也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。

这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

相信它会给大家带来很多收获:

[外链图片转存中…(img-I45NMHyq-1714800982415)]

[外链图片转存中…(img-4TmDsD7F-1714800982415)]

资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 29
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值