Android性能优化整理

高质量的应用目标:快、稳、省、小

  • 快:使用时避免出现卡顿,响应速度快,减少用户等待的时间,满足用户期望。

  • 稳:减低 crash 率和 ANR 率,不要在用户使用过程中崩溃和无响应。

  • 省:节省流量和耗电,减少用户使用成本,避免使用时导致手机发烫。

  • 小:安装包小可以降低用户的安装成本


1. 卡顿优化

归根结底:显示问题

Android系统显示原理

应用层绘制好后,通过跨进程通信把需要的数据传递到系统层,通过系统层的SurfaceFlinger把数据渲染到显示屏幕上,通过Android的刷新机制来刷新数据。

应用层

  • View绘制核心步骤:Measure、Layout、Draw
  • 从 ViewRootImp类的performTraversals() 方法开始执行,Measure和Layout都是通过递归来获取View的大小和位置,并且以深度作为优先级,层级越深、元素越多、耗时也就越长

绘制方式

  • 软件绘制(CPU)
  • 硬件加速(GPU,3.0后全面支持)

应用层GPU绘制缺点:

  1. 耗电
    GPU功耗比CPU高

  2. 兼容问题
    某些接口和函数不支持硬件加速

  3. 内存大
    使用OpenGL接口至少需要8MB内存

绘制过程

  • CPU准备数据,通过Driver层把数据交给CPU渲染
  • CPU主要负责Measure、Layout、Record、Execute的数据计算工作
    GPU负责栅格化(Rasterization)、渲染
  • 图形API不允许CPU直接与GPU进行通信,通过图形驱动层(Graphics Driver)来连接这两部分
  • 图形驱动层维护了一个队列,CPU把display list 添加到队列中,GPU从中取出数据进行绘制,最终显示。

系统层

通过系统级进程中的SurfaceFlinger服务来真正把需要显示的数据渲染到屏幕上

  • 响应客户端事件,创建Layer与客户端的Surface建立连接。

  • 接收客户端数据及属性,修改Layer属性,如尺寸、颜色、透明度等。

  • 将创建的Layer内容刷新到屏幕上。

  • 维持Layer的序列,并对Layer最终输出做出裁剪计算。

  • 应用层绘制到缓存区,SurfaceFlinger把缓存区数据渲染到屏幕,由于是不同的进程,所以使用Android的匿名共享内存SharedClient缓存需要显示的数据来达到目的。

  • FPS表示每秒传递的帧数。Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染。主要场景执行动画或滑动ListView。

  • CPU或GPU负载过重,布局过于复杂,16ms不能进行渲染,UI层叠太多,动画执行次数过多,刷新不及时等容易丢帧。


刷新机制

双缓冲

Framebuffer带来残影问题

VSYNC(Vertical Synchronization)

CPU主动查询保证数据是否准备好,效率低
定时中断,收到信号,CPU处理各帧数据

Choreographer:起调度作用

收到VSYNC信号,调用用户设置的回调函数

  • CALLBACK_INPUT : 输入事件有关
  • CALLBACK_ANIMATION : 与动画有关
  • CALLBACK_TRAVERSAL : UI控件绘制有关

卡顿根本原因

  1. 绘制任务太重,绘制一帧内容耗时太长
  2. 主线程太忙,根据系统传递过来的VSYNC信号来时还没准备好数据导致丢帧。

主线程主要做以下几个方面工作

  • UI生命周期控制
  • 系统事件处理
  • 消息处理
  • 界面布局
  • 界面绘制
  • 界面刷新
  • 除此之外,应该尽量避免将其他处理放在主线程中,特别复杂的数据计算和网络请求等。

性能分析工具

1. Profile GPU Rendering

  • 一个图形监测工具,能实时反应当前绘制的耗时

  • 横轴表示时间,纵轴表示每一帧的耗时

  • 随着时间推移,从左到右的刷新呈现

  • 提供一个标准的耗时,如果高于标准耗时,就表示当前这一帧丢失

  • 可以通过adb shell dumpsys gfxinfo com..把具体耗时输出到日志来进行查看分析

2. TraceView

  • TraceView是Android SDK自带的工具,用来分析函数调用过程,可以对Android的应用程序以及Framework层的代码进行性能分析。

  • 它是一个图形化的工具,最终会产生一个图表,用于对性能分析进行说明,可以分析到每一个方法的执行时间,其中可以统计出该方法调用次数和递归次数,实际时长等参数维度,使用非常直观,分析性能非常方便。

3. Systrace

  • Systrace是Android 4.1及以上版本提供的性能数据采样和分析工具,它是通过系统的角度来返回一些信息。

  • 它可以帮助开发者收集Android关键子系统,如Surfaceflinger、WindowManagerService等Framework部分关键模块、服务、View系统等运行信息,从而帮助开发者更直观地分析系统瓶颈,改进性能。

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


卡顿优化建议

1 布局优化(HieracrchyViewer&Lint)

  • 减少层级。
  • 合理使用RelativeLayout和LinerLayout,合理使用Merge。
  • 提高显示速度。
  • 使用ViewStub。
  • 布局复用。
  • 通过标签来提高复用。
  • 尽可能少用wrap_content。
  • 增加布局measure时计算成本,在已知宽高为固定值时,不用wrap_content
  • 删除控件中无用的属性。

2 避免过度绘制

过度绘制
在屏幕上的某个像素在同一帧的时间内被绘制了多次,从而浪费了多余的CPU以及GPU。

布局上的优化:

  • 移除XML中非必须的背景
  • 移除Window默认的背景
  • 按需显示占位背景图片

自定义View优化:
使用 canvas.clipRect()来帮助系统识别那些可见的区域,只有在这个区域内才会被绘制。

开发者选项:调试GPU过度重绘

  • 无色:1
  • 蓝色:1+
  • 绿色:2+
  • 淡红:3+(不超过1/4屏可接受)
  • 深红:4++(严重影响性能,需优化)

3 启动优化

  • 通过对启动速度的监控,发现影响启动速度的问题所在,优化启动逻辑,提高应用的启动速度。

  • 启动主要完成三件事:
    UI布局
    绘制
    数据准备

  • UI布局。
    应用一般都有闪屏页,优化闪屏页的UI布局,可以通过Profile GPU Rendering检测丢帧情况。使用HierarchyView检查布局优化

  • 启动加载逻辑优化。
    可以采用分布加载、异步加载、延期加载策略来提高应用启动速度。

  • 数据准备。
    数据初始化分析,加载数据可以考虑用线程初始化等策略。

4 合理的刷新机制

  • 频繁刷新会增加资源开销,并且可能导致卡顿发生,因此:

  • 尽量减少刷新次数。

  • 尽量避免后台有高的CPU线程运行。

  • 缩小刷新区域。

5 提升动画性能

  • 帧动画:一组图片按顺序显示。图片过多,消耗资源,效果最差。

  • 补间动画:只需要定义开始和结束关键帧,之间效果自动生成。
    局限性:
    只能用于View对象,只有继承于View或View的控件;
    只有四种动画:淡入淡出、缩放、平移、旋转。
    只改变了显示效果,没有改变真正属性。

  • 属性动画:可以应用于View,和任何对象。持续时间、时间插值、重复次数行为、动画系和、帧刷新延迟。相对于不见动画,重绘少,性能更佳。

  • 在实现动画效果时,需要根据不同场景选择合适的动画框架来实现。有些情况下,可以用硬件加速方式来提供流畅度。


2. 内存优化

Android内存管理机制

  • Android应用都是在 Android的虚拟机上运行,应用程序的内存分配与垃圾回收都是由虚拟机完成的。

  • 在Android系统,虚拟机有两种运行模式:Dalvik和ART。

工具1 Memory Monitor

Memory Monitor是一款使用非常简单的图形化工具,可以很好地监控系统或应用的内存使用情况,主要有以下功能:

  • 显示可用和已用内存,并且以时间为维度实时反应内存分配和回收情况。
  • 快速判断应用程序的运行缓慢是否由于过度的内存回收导致。
  • 快速判断应用是否由于内存不足导致程序崩溃。

工具2 Heap Viewer

Heap Viewer的主要功能是查看不同数据类型在内存中的使用情况,可以看到当前进程中的Heap Size的情况,分别有哪些类型的数据,以及各种类型数据占比情况。通过分析这些数据来找到大的内存对象,再进一步分析这些大对象,进而通过优化减少内存开销,也可以通过数据的变化发现内存泄漏。

工具3 Allocation Tracker

Memory Monitor和Heap Viewer都可以很直观且实时地监控内存使用情况,还能发现内存问题,但发现内存问题后不能再进一步找到原因,或者发现一块异常内存,但不能区别是否正常,同时在发现问题后,也不能定位到具体的类和方法。这时就需要使用另一个内存分析工具Allocation Tracker,进行更详细的分析,Allocation Tracker可以分配跟踪记录应用程序的内存分配,并列出了它们的调用堆栈,可以查看所有对象内存分配的周期

工具4 Memory Analyzer Tool(MAT)

MAT是一个快速,功能丰富的Java Heap分析工具,通过分析Java进程的内存快照HPROF分析,从众多的对象中分析,快速计算出在内存中对象占用的大小,查看哪些对象不能被垃圾收集器回收,并可以通过视图直观地查看可能造成这种结果的对象。


常见内存泄漏场景

  • 资源性对象未关闭。比如Cursor、File文件等,往往都用了一些缓冲,在不使用时,应该及时关闭它们。

  • 注册对象未注销。比如事件注册后未注销,会导致观察者列表中维持着对象的引用。

  • 类的静态变量持有大数据对象。

  • 非静态内部类的静态实例。

  • Handler临时性内存泄漏。如果Handler是非静态的,容易导致Activity或Service不会被回收。

  • 容器中的对象没清理造成的内存泄漏。

  • WebView。WebView存在着内存泄漏的问题,在应用中只要使用一次WebView,内存就不会被释放掉。


LeakCanary 第三方开源库

这是一个检测内存泄漏的开源库,可以在发生内存泄漏时告警,并且生成leak tarce分析泄漏位置,同时可以提供Dump文件进行分析。


优化内存空间

  • 对象引用。
    强引用、软引用、弱引用、虚引用四种引用类型,根据业务需求合理使用不同,选择不同的引用类型。

  • 减少不必要的内存开销。
    注意自动装箱,增加内存复用,比如有效利用系统自带的资源、视图复用、对象池、Bitmap对象的复用。

  • 使用最优的数据类型。
    比如针对数据类容器结构,可以使用ArrayMap数据结构,避免使用枚举类型,使用缓存Lrucache等等。

  • 图片内存优化。
    可以设置位图规格,根据采样因子做压缩,用一些图片缓存方式对图片进行管理等等。


3. 稳定性优化

  • 提高代码质量。比如开发期间的代码审核,看些代码设计逻辑,业务合理性等。

  • 代码静态扫描工具。常见工具有Android Lint、Findbugs、Checkstyle、PMD等等。

  • Crash监控。把一些崩溃的信息,异常信息及时地记录下来,以便后续分析解决。

  • Crash上传机制。在Crash后,尽量先保存日志到本地,然后等下一次网络正常时再上传日志信息。


4. 耗电优化

  • 5.0之后专门引入了一个获取设备上电量消耗信息的API:Battery Historian。一款由Google提供的Android系统电量图形化数据分析工具,直观地展示出手机的电量消耗过程,通过输入电量分析文件,显示消耗情况,最后提供一些可供参考电量优化的方法。

  • 计算优化,避开浮点运算等。

  • 避免WakeLock使用不当。
    休眠意味着CPU频率降低,需要做一些需要大量运算的任务时,所以需要唤醒CPU

  • 使用JobScheduler

--

5. 安装包大小瘦身

  • 代码混淆。
    使用ProGuard代码混淆器工具,它包括压缩、优化、混淆等功能。
  • 资源优化。
    比如使用Android Lint删除冗余资源,资源文件最少化等。
  • 图片优化。
    比如利用AAPT工具对PNG格式的图片做压缩处理,降低图片色彩位数等。
  • 避免重复功能的库,使用WebP图片格式等。
  • 插件化。
    比如功能模块放在服务器上,按需下载,可以减少安装包大小。

你可能感兴趣的:(Android性能优化整理)