性能优化-绘制优化

2020-02-18  本文已影响0人  Vinson武

前言

卡顿场景可分为以下四类:

  1. UI绘制:绘制、刷新
  2. 应用启动:安装启动、冷启动、热启动
  3. 页面跳转:页面间切换、前后台切换
  4. 事件响应:按键、系统事件、滑动

这四种卡顿场景的根本原因又可以分为两大类:

  1. 界面绘制:主要原因是绘制的层级深、页面复杂、刷新不合理
  2. 数据处理:导致这种卡顿场景的原因是数据处理量太大,一般分为三种情况:

Android系统显示原理

Android的显示过程可以简单概括为:Android应用程序把经过测量、布局、绘制后的surface缓存数据,通过SurfaceFlinger把数据渲染到屏幕上,通过Android的刷新机制来刷新数据。

绘制原理

应用层

在Android的每个view绘制中又三个核心步骤:Mesasure、Layout、Draw。通过Measure和Layout来确定当前需要绘制的view所在的大小和位置,通过绘制(Draw)到surface。

Measure和Layout都是递归来获取view的大小和位置,并且以深度作为优先级,因此层级越深,元素越多,耗时也就越长

系统层

应用层和系统层是两个不同进程,在Android的显示系统,使用匿名共享内存:SharedClient,每个应用和SurfaceFlinger之间都会创建一个SharedClient。在每个SharedClient中,最多可以创建31个ShardBufferStack,每个Surface都对应一个ShardBufferStack,也就是一个window。 一个SharedClient对应一个Android应用程序,意味着一个Android应用程序最多可以包含31个窗口

显示整体流程分为三个模块:应用层绘制到缓存区,SurfaceFlinger把缓存区数据渲染到屏幕,由于是两个不同的进程,所以使用Android的匿名共享内存SharedClient缓存需要显示的数据来达到目的。

知道绘制原理后,那么绘制一个单元多长时间才是合理的?
——在理想情况下,60FPS(Frames Per Second 每秒传递的帧数)就感觉不到卡,这意味着每个绘制时长应该在16ms以内。

Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染。若每次都成功就能达到流畅画面的60FPS。若某个操作耗时较久,系统在得到VSYNC信号时就无法正常渲染,这样就会发生丢帧现象。

==卡顿的根本原因==

影响绘制的根本原因有以下两方面:

  1. ==绘制任务太重==,绘制一帧内容耗时太长。
  2. ==主线程太忙==,导致VSync信号来时还没有准备好数据导致丢帧。

性能分析工具

性能问题不容易复现,在分析性能问题时需要借助相应的调试工具,比如查看Layout层次的Hierarchy View、Android系统自带的 Profile GPU卡顿检测工具和静态代码检查工具Lint,以及性能分析常用的TraceView和SysTrace等。

卡顿检测工具

Profile GPU Rendering是Android4.1系统开始提供的开发辅助工具,可在开发者选项中打开(华为手机是:GPU呈现模式分析按钮)

特点:

各种颜色含义


image.png

技巧:
在实际开发中,图形不便做数据分析,可通过:adb shell dumpsys gfxinfo com.##.##(包名)把具体的耗时输出到日志中来分析。

对大部分应用来说丢失几帧影响不大,只需保证大部分在警戒线下即可。通过Profile GPU Rendering发现有问题对页面后,可通过另一个工具Hierarchy Viewer来查看布局层次和每个view所花时间具体定位。

TraceView

TraceView是AndroidSDK自带的工具,用来分析函数调用过程,可以分析到应用具体每一个方法的执行时间

  1. 使用方法

在使用TraceView分析问题之前需要得到一个*.trace的文件,然后通过TraceView来分析。trace文件的获取方法有两种:

//在开始监控的地方,保存在"/sdcard/trace_name.trace"
Debug.startMethodTracing("trace_name");
//...
//stop trace
Debug.stopMethodTracing();
  1. TraceView 视图说明
    TraceView视图分两个部分,上半部分为时间片面板,下半部分为分析面板。

SysTrace UI性能分析

Systrace是Android4.1以上版本提供的性能数据采样和分析工具。功能包括跟踪系统的I/O操作、内核工作队列、CPU负载等。能直观查看CPU周期消耗的具体时间,用不同颜色来突出问题严重性,并提供解决建议。

注意:由于Systrace从系统角度返回一些信息,并不能定位到具体耗时的方法,要具体分析原因要借助TraceView

  1. Systrace 使用方法
cd android-sdk/platform-tools/systrace
python systrace.py --time=10 -o mytrace.html sched gfx view wm

具体命令查看官方文档

(1)Trace嵌套时,endSection()方法只会结束离它最近的一个beginSection()。所以要保证endSection和beginSection调用次数匹配。

(2)Trace的begin和end必须在同一线程中执行。

public void ProcessPeople{
  Trace.beginSection("ProcessPeople");
  try{
      Trace.beginSection("Process One");
      try{
          //code
      }finally{
          Trace.endSection(); //end Process One
      }
      Trace.beginSection("Process Two");
      try{
          //code
      }finally{
          Trace.endSection(); //end Process Two
      }
  }finally{
      Trace.endSection(); //end ProcessPeople
  }
}
  1. 分析Systrace报告

通过前面方法获取到的trace.html文件,需要用Chrome打开,其中和UI绘制关系紧密的是Alerts和Frame两个数据。

布局优化

布局是否合理主要影响的是页面测量时间的多少,如果层级太深,每增加一层则会增加更多的页面显示时间。

常用布局优化工具

1. Hierarchy View

Hierarchy View是Android SDK自带的调试工具,用来检查Layout嵌套及绘制时间,以可视化的布局角度获取Layout布局设计和各种属性信息。

使用:在Android Studio中打开Android Device Monitor菜单,直接打开Hierarchy View

一个应用界面非常多,如果一个个用Hierarchy View分析效率低,可以用另一个工具Lint,用于检查所有页面的层级,并把深度高于N的界面输出,然后在用Hierarchy View仔细分析

2. 布局层级检查

Android Lint是ADT 16之后引入的代码检查工具,通过代码静态检查,可以发现潜在的代码问题,并给出优化建议。

使用前可在File -> Setting -> Inspections -> Android Lint中配置扫描规则和缺陷级别。

在Android studio中启动Lint:从菜单栏选择Analyze -> Inspect Code,进去后选择扫描范围扫描。

布局优化方法

通过减少Layout层级,减少测量、绘制时间,提高复用性三方方面来优化布局,,优化的目的是减少层级,让布局扁平化,以提高绘制的时间,提高布局的复用性。

1. 减少层级

减少层级的两个常用方案:

合理使用RelativeLayout和LinearLayout

RelativeLayout相对LinearLayout能够减少布局层级,但也存在性能低的问题,原因是RelativeLayout会对子view做两次测量,因为依赖关系可能和布局中view顺序不同,在确定子view位置时,需先给所有子view做一次排序。

布局原则:

合理使用Merge

Merge是合并的意思,可以有效优化某些符合条件的多余层级。使用场景如下:

Merge使用要求:

2. 提高显示速度

有时需要某个布局在一开始不显示,在某个条件下才显示,可以通过visable属性来控制,但这样效率非常低,因为虽然布局隐藏来,但还在布局中,仍会解析这些布局。可以使用ViewStub控件来解决这个场景并提高效率。

ViewStub是一个轻量级的View,它是一个看不见的,并不占布局位置,占用资源非常小的视图对象。

使用ViewStub注意的点:

ViewStub主要使用场景:

3. 布局复用

开发过程中可以将一些公共的布局抽离出来作为一个布局文件,然后在需要使用的地方通过<include/>标签来实现引入。

对布局优化的总结

避免过度绘制

过度绘制的主要原因

过度绘制检测工具

通过手机设置中开发者选项,打开Show GPU Overdraw选项(调试 GPU 过度绘制),打开后会有不同的颜色区域表示不同的过度绘制次数。不同颜色含义如下:

我们的目标是减少红色Overdraw,看到更多蓝色或无色区域。

如何避免过度绘制

  1. 布局上的优化

在Android自带的一些主题时activity往往会设置一个默认的背景,这个背景有DecorView持有。当自定义布局有一个全屏背景时,DecorView的背景此时对我们来说是无用的,但会产生一次Overdraw,因此可以移除

protect void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    this.getWindow().setBackgroundDrawaable(null);
}
  1. 自定义View优化

自定义view能减少layout的层级,但在实际绘制时容易出现过度绘制。可以通过canvas.clipRect()来帮组系统识别那些可见的区域,然后只在这个区域绘制。canvas.quickreject()来判断是否没和某个矩形相交,从而跳过那些非矩形区域内的绘制操作。

启动优化

应用启动流程

启动分两种类型:冷启动和热启动

启动 -> Application -> attachBaseContext() -> onCreate() -> Activity生命周期

启动耗时检测

  1. adb shell am:使用adb shell获取应用真实启动时间代码
adb shell am start -W [packageName]/[packageName.AppstartActivity]

执行后得到三个时间

但这个方法只能得到固定某个阶段耗时,不能知道具体方法耗时。可用代码打点方式来得到具体方法耗时。

  1. 代码打点

启动优化方案

启动主要完成三件事:UI布局、绘制和数据准备,因此优化启动速度也是优化这三个过程。

  1. UI布局优化
  1. 启动加载逻辑优化
    数据按需实现加载逻辑

合理的刷新机制

合理的刷新机制要注意以下几点;

减少刷新次数

  1. 控制刷新频率:比如刷新进度调可1%刷新一次,而不是实时刷新
  2. 避免没有必要的刷新:先判断是否需要刷新,比如数据没变化、控件不在可见区域就没必要刷新。

避免后台线程影响

后台线程如果开销很大,占用CPU过高,导致系统频繁GC和CPU时间片资源紧张,有可能会导致页面的卡顿。因此在需要迅速刷新的情况下避免这类线程在高峰工作。

缩小刷新区域

采用局部刷新来节约资源

invalidate(Rect dirty)
invalidate(int left, int top, int right, int bottom)

提升动画性能

从三个纬度来对比动画性能

优化建议

使用硬件加速注意几点:

参考书籍:《Android应用性能优化最佳实践》

上一篇下一篇

猜你喜欢

热点阅读