Android——APP性能如何优化
Posted Yawn,
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android——APP性能如何优化相关的知识,希望对你有一定的参考价值。
1. 四个方面
可以把用户体验的性能问题主要总结为4个类别:
- 流畅
- 稳定
- 省电、省流量
- 安装包小
性能问题的主要原因归根到底,也就是内存使用、代码效率、合适的策略逻辑、代码质量、安装包体积这一类问题,整理归类如下:
主要就四点:
- 快:使用时避免出现卡顿,响应速度快,减少用户等待的时间,满足用户期望。
- 稳:减低 crash 率和 ANR 率,不要在用户使用过程中崩溃和无响应。
- 省:节省流量和耗电,减少用户使用成本,避免使用时导致手机发烫。
- 小:安装包小可以降低用户的安装成本。
2. 卡顿优化
按场景可以分为:UI 绘制、应用启动、页面跳转、事件响应
这几种卡顿场景的根本原因其实可以分为:
- 界面绘制 :主要原因是绘制的层级深、页面复杂、刷新不合理,由于这些原因导致卡顿的场景更多出现在UI和启动后的初始界面以及跳转到页面的绘制上。
- 数据处理 :导致这种卡顿场景的原因是数据处理量太大,一般分为三种情况
- (1)数据在处理UI线程
- (2)数据处理占用CPU高,导致主线程拿不到时间片
- (3)内存增加导致GC频繁,从而引起卡顿。
3. android系统显示原理
可以简单概括为:
- Android应用程序把经过测量、布局、绘制后的Surface缓存数据,通过SurfaceFlinger把数据渲染到显示屏幕上, 通过Android的刷新机制来刷新数据。
- 也就是说应用层负责绘制,系统层负责渲染,通过进程间通信把应用层需要绘制的数据传递到系统层服务,系统层服务通过刷新机制把数据更新到屏幕上。
View绘制中有三个核心步骤:Measure、Layout、Draw
真正把需要显示的数据渲染到屏幕上,是通过系统级进程中的SurfaceFlinger服务来实现的:
- 响应客户端事件,创建Layer与客户端的Surface建立连接。
- 接收客户端数据及属性,修改Layer属性,如尺寸、颜色、透明度等。
- 将创建的Layer内容刷新到屏幕上。
- 维持Layer的序列,并对Layer最终输出做出裁剪计算。
4. 卡顿的根本原因与优化
影响绘制的根本原因有以下两个方面:
- 绘制任务太重,绘制一帧内容耗时太长。
- 主线程太忙,根据系统传递过来的VSYNC信号来时还没准备好数据导致丢帧。
一般来说主线程只做以下工作:
- UI生命周期控制
- 系统事件处理
- 消息处理
- 界面布局
- 界面绘制
- 界面刷新
优化建议:
4.1 布局优化
主要通过减少层级、减少测量和绘制时间、提高复用性三个方面入手:
- 减少层级。合理使用RelativeLayout和LinerLayout,合理使用Merge。
- 提高显示速度。使用ViewStub,它是一个看不见的、不占布局位置、占用资源非常小的视图对象。
- 布局复用。可以通过标签来提高复用。
- 尽可能少用wrap_content。wrap_content 会增加布局measure时计算成本,在已知宽高为固定值时,不用wrap_content 。
- 删除控件中无用的属性
4.2 避免过度绘制
过度绘制是指在屏幕上的某个像素在同一帧的时间内被绘制了多次,从而浪费了多余的CPU以及GPU资源。
- 布局上的优化。移除XML中非必须的背景,移除Window默认的背景、按需显示占位背景图片
- 自定义View优化。使用 canvas.clipRect()来帮助系统识别那些可见的区域,只有在这个区域内才会被绘制。
4.3 启动优化
启动主要完成三件事:UI布局、绘制和数据准备。
启动速度优化就是需要优化这三个过程:
- UI布局。应用一般都有闪屏页,优化闪屏页的UI布局,可以通过Profile GPU Rendering检测丢帧情况。
- 启动加载逻辑优化。可以采用分布加载、异步加载、延期加载策略来提高应用启动速度。
- 数据准备。数据初始化分析,加载数据可以考虑用线程初始化等策略。
4.4 刷新率
因为数据的变化,需要刷新页面来展示新的数据,但频繁刷新会增加资源开销,并且可能导致卡顿发生。
- 尽量减少刷新次数。
- 尽量避免后台有高的CPU线程运行。
- 缩小刷新区域。
4.5 内存优化
Java对象生命周期:
- 创建阶段->应用阶段->不可见阶段->不可达阶段->收集阶段->终结阶段->对象空间重新分配阶段
内存分配:
- 在Android系统中,内存分配实际上是对堆的分配和释放。当一个Android程序启动,应用进程都是从一个叫做Zygote的进程衍生出来,系统启动 Zygote 进程后,为了启动一个新的应用程序进程,系统会衍生Zygote进程生成一个新的进程,然后在新的进程中加载并运行应用程序的代码。
- 其中,大多数的RAM pages被用来分配给Framework代码,同时促使RAM资源能够在应用所有进程之间共享。
- 但是为了整个系统的内存控制需要,Android系统会为每一个应用程序都设置一个硬性的Dalvik Heap Size最大限制阈值,整个阈值在不同设备上会因为RAM大小不同而有所差异。如果应用占用内存空间已经接近整个阈值时,再尝试分配内存的话,就很容易引起内存溢出的错误。
常见内存泄漏场景:
- 资源性对象未关闭。比如Cursor、File文件等,往往都用了一些缓冲,在不使用时,应该及时关闭它们。
- 注册对象未注销。比如事件注册后未注销,会导致观察者列表中维持着对象的引用。
- 类的静态变量持有大数据对象。
- 非静态内部类的静态实例。
- Handler临时性内存泄漏。如果Handler是非静态的,容易导致Activity或Service不会被回收。
- 容器中的对象没清理造成的内存泄漏。
- WebView。WebView存在着内存泄漏的问题,在应用中只要使用一次WebView,内存就不会被释放掉。
内存泄漏避免: 静态集合类,对象集合属性改变,异步调用activity可能不被释放,监听器太多,数据库连接,网络连接太多,资源未关闭(file,stream,广播)
优化内存空间:
- 对象引用。强引用、软引用、弱引用、虚引用四种引用类型,根据业务需求合理使用不同,选择不同的引用类型。
- 减少不必要的内存开销。注意自动装箱,增加内存复用,比如有效利用系统自带的资源、视图复用、对象池、Bitmap对象的复用。
- 使用最优的数据类型。比如针对数据类容器结构,可以使用ArrayMap数据结构,避免使用枚举类型,使用缓存Lrucache等等。
- 图片内存优化。可以设置位图规格,根据采样因子做压缩,用一些图片缓存方式对图片进行管理等等。
4.6 减少安装包大小的常用方案:
- 代码混淆。使用ProGuard代码混淆器工具,它包括压缩、优化、混淆等功能。
- 资源优化。比如使用Android Lint删除冗余资源,资源文件最少化等。
- 图片优化。比如利用AAPT工具对PNG格式的图片做压缩处理,降低图片色彩位数等。
- 避免重复功能的库,使用WebP图片格式等。
- 插件化。比如功能模块放在服务器上,按需下载,可以减少安装包大小。
以上是关于Android——APP性能如何优化的主要内容,如果未能解决你的问题,请参考以下文章