当前位置 博文首页 > Yawn:Android——APP性能如何优化

    Yawn:Android——APP性能如何优化

    作者:[db:作者] 时间:2021-08-02 18:39

    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图片格式等。
    • 插件化。比如功能模块放在服务器上,按需下载,可以减少安装包大小。
    cs
    下一篇:没有了