持续创造,加快生长!这是我参与「日新计划 · 10 月更文挑战」的第23天,点击检查活动概况

前置知识

  • 有Android开发根底
  • 了解Android运转原理

前语

在上一篇文章 初识功能优化 中咱们提到咱们需求从流畅性优化资源优化稳定性优化系统级优化 这四个层面来对Android中的软件做优化。可是咱们仅仅简略的对其进行介绍,以及举了一些流畅性优化的实战例子。下面,咱们就对这四类优化点翻开进行解说(文章参数理论和原因,无实战 demo 展现)。

流畅性优化

主线程模型

了解 Android 的流畅性优化之前,咱们需求先了解Android的线程结构。在 Android 中,有一个主线程模型,其中一切的制作以及交互都是在主线程中进行的,所以,当咱们编写的某类代码是需求在主线程中运转的,那么这类代码必然会影响到咱们的制作等,继而影响到流畅性问题。

下图之中,展现了咱们哪类代码操作代码是会影响到主线程。

  1. System Events(系统工作)

    例如需求封闭、开启某个页面,这些都是需求通知咱们的系统的来完结的,这些便是系统工作。它会触发到主线程的耗时操作。

  2. Input Events(输入工作)

    输入工作并非指单纯的在输入框输入信息的工作,而是在手机上进行操作。由于手机自身能够被笼统的指代为一个输入输出的设备。在触摸屏上任意的点击都是一个输入工作,它都是在主线程中完结的,具体的流程能够查阅 View系统(上)

  3. Application(运用工作)

    咱们APP的发动都是要经过运用工作,而各种生命周期的初始化相关的回调、初始化也是要经过它。例如各类发动的 SDK 都是放在 Application 类中初始化的,这都是要在主线程中进行的。

  4. Services(服务工作)

    这一点大家也许有点疑惑,后台服务为什么会是在主线程的呢?咱们不是一般新开一个线程在后台履行耗时使命的么?上述的两点其实是不对立的,仅仅咱们平常的理解也许有误,以为 Services 作为后台使命便是在子线程才对。但现实上, Services 是运转在主线程中的,即使它是在后台履行的,而咱们需求履行耗时使命的时分,再在 Services 中创建子线程来履行这个耗时使命 。

  5. Alarm(守时工作)

    守时工作中,由于它默认子线程是不安全的,主线程才是安全的,所以是需求到主线程去履行的。

UI制作 虽然是在主线程中的,可是咱们的代码是无法去操控它的,这是系统进行操控的。咱们只能输入需求制作什么,可是不能影响其制作的流程。

界面更新以及卡顿

界面更新的VSync

知晓主线程模型后,咱们来看一下 界面是怎么改写

下面的一图是介绍 Android 中的 VSync 机制,VSync 咱们能够简略的理解为是一种屏幕改写的信号,它会每隔一段时刻就会改写一次屏幕。(Vsync 是什么、View系统(下) 或 Android图形显现系统 可检查更多信息)

**笔直同步(VSync):**当屏幕从缓冲区扫描完一帧到屏幕上之后,开端扫描下一帧之前,宣布的一个同步信号,该信号用来切换前缓冲区和后缓冲区。

而在 Android 中,VSync 信号的回调一般会在主线程中每隔16ms履行一次,而咱们经过频率核算公式来核算一下: f=1Tf=\frac{1}{T} ,当 T=16msT=16ms 时分,咱们能够得出 f=62.5HZf=62.5HZ 这个便是咱们常用的 60fps60fps

在咱们的视觉感知中,24fps24fps 一般能够让人眼感知到线性动作了,而人能感知到不卡顿的最低帧数则为 25fps25fps。在 Vsync 机制中的 60fps60fps 则能够让设备呈现愈加艳丽的作用,关于当下热炒的 90fps90fps120fps120fps 则是让感觉上愈加顺滑罢了,可是关于与实践和功耗的平衡,高于 60fps60fps 是没有必要的。

如下图,UI Draw 会在 16ms 就履行一次,所以咱们的需求让咱们的制作流程在 16ms 内履行完才不会呈现卡顿问题。

所以说,假如咱们不影响界面的更新,让每次制作流程都能够保持在16ms以下,那么就不会呈现卡顿问题了。

三类主要的卡顿以及其原因

  • 输入工作无法即时呼应

    这类卡顿主要表现为咱们滑动屏幕的时分,屏幕底子无法呼应。这是由于咱们在主线程中履行了一段非常耗时的、与工作无关的代码,而由于这段代码还在履行,所以输入工作底子无法履行,也无法制作出咱们的滑动作用了。

  • 输入工作立刻呼应,但其耗时较长

    这类卡顿中,输入工作是立即呼应的了,可是由于咱们又在输入工作的分发中做了许多核算逻辑等耗时的操作,所以还是会呈现卡顿。其表现出来的作用是,滑动的时分一卡一卡的,这是由于输入工作的履行超过了16ms了,导致了丢帧的问题。

  • UI Draw 之外需求在主线程中履行的使命耗时长

    咱们知道,主线程中不单只要 UI 的制作使命,还有其他的例如 Application 使命也是需求放置在主线程中履行的。这些使命假如不做处理,也一股脑的放置在主线程中履行,那么也会导致其占用时刻过长,使得 APP 呈现丢帧的问题。

处理卡顿问题

咱们现已经知道了三大类卡顿的原因,其归结来说的原因便是主线程中呈现了不必要的耗时操作,导致最终主线程的UI制作呈现堵塞或许溢出。那么咱们处理卡顿、做流畅性优化的办法也是很清晰了,那便是让主线程尽量只做交互(Input Event)以及改写(UI Draw)。当然许多需求在主线程中的代码是无法防止的,可是咱们尽量使其缩小,让一切的耗时代码都在子线程中运转,这姿态使得其削减丢帧,能够愈加的连接顺滑。

没有VSync会怎么样?

上述讲到了 VSync 的作用以及卡顿的原因和处理,咱们知道 VSync 信号能够用于同步改写页面。那若是没有 VSync 信号,咱们的页面会呈现什么样的问题?

其实会呈现画面撕裂。画面撕裂是什么呢?如下图中赤色框中的图面,与上边呈现了撕裂,这种便是画面撕裂。其呈现的原因是上一帧的页面还在制作中,下一帧页面就持续占用资源制作了,所以会呈现几帧的页面一起制作在一个页面中,呈现了画面撕裂感。

那为何映入 VSync 信号之后就不会有画面撕裂问题了呢?

在显现一张图片的时分,其流程为:GPU进⾏渲染—>帧缓存区⾥ —>显现操控器—>读取帧缓存区信息(位图) —> 数模转化(数字信号处—>模 拟型号) —>(逐⾏扫描)显现。
正常的情况下,显现器彻底显现完一帧后,帧缓存区更新一帧,这样便不会有撕裂问题,但现实并非如此。
显卡输出帧的速度比显现器快,显现器的处理速度跟不上显卡,在显现器处理显卡丢过来的第1帧的时分,第2帧就又到了(帧缓存区已更新),导致同一个画面一起呈现1、2两帧,撕裂就产生了

在没有 VSync 信号的时分,一旦GPU渲染完后就会交由屏幕去将其制作出来,那么 CPU 和 GPU 处理的工作有长有短,一旦两帧呈现制作冲突,就会呈现画面撕裂问题了。

所以说,处理画面撕裂的中心是决议好数据的交换机遇(制作机遇)由谁来操控。在制作中,不该该是 CPU 处理写入之后就立即制作,而应该是由屏幕渲染完一帧之后才去制作制作下一帧。可是屏幕不是操控器,它无法操控什么时分进行制作,可是它能够传递 VSync 信号给 Android 系统,凭借 VSync 信号,Android 就能够让 CPU 在新的一帧开端的时分立即处理显现问题了。

VSYNC 信号是由屏幕(显现设备)产生的,并且以 60fps 的固定频率发送给 Android 系统,Android 系统中的 SurfaceFlinger 接收发送的 VSYNC 信号。VSYNC 信号表明可对屏幕进行改写而不会产生撕裂。

图片中未对 VSync 信号进行处理,导致呈现卡顿问题。

资源优化

资源是什么?

资源指的是:Android 手机的软件和硬件资源,浅显意义上运用依赖于移动端的有限资源和系统规则的数值。例如:功耗、存储、流量、系统参数、CPU、内存等。

咱们对上述的资源进行优化的时分,其并非无关联的、相互隔离的,例如流量耗费大,那么功耗耗费也会大,内存和存储的耗费也会大。可是咱们需求优化某一个点的时分,是需求聚集于其中这一点进行优化的。

当然,如前文所说咱们运用的设备也是在不断地优化的,可是并非说等着硬件的优化,咱们的软件能跑就行。关于资源优化,咱们寻求的是利用最小的资源达到最好的作用,这是很有挑战性,对自我提升也很高的工作。

Android 能做哪些资源优化

上图中展现了关于当下技能特征的满意度,咱们会发现上述的点其实都不算高。无论是内存/存储、电量或许是流量等等方面都是需求咱们持续优化的点。而右图指的是假如后台的进程假如许多的话,使得内存占用许多,导致前台的APP也会收到内存的约束变得卡顿。

上图中对音量的优化其实收益也是很大的。例如当下的自媒体渠道抖音,它便是在端侧进行了音量优化,取得了很大的收益。由于每一个人拍视频的音量和背景嘈杂度都是不一样的,所以咱们需求在上传视频到渠道的时分进行音量优化,对各种音量进行优化、拟合到同一水平,这姿态能够使得用户在翻开不同视频的时分,视频的音量不会影响到用户的体会。

而关于亮度的优化,能够使得咱们的功耗下降,节省手机有限的电量。上面左图能够看出,深色形式对电量的影响是很显著的。而一起在优化亮度的时分,咱们也能够找出功耗与体会的平衡点,使得功耗低的时分,咱们的体会感也是最好的。这一点能够在右图中看出。

稳定性优化

关于稳定性优化,咱们主要讲的点是 ANR,而其他的崩溃等则是需求尽或许的抹去,这儿暂不做剖析。ANR 是运用长时刻处于堵塞状况的时分,系统会触发 ANR ,然后系统会询问是否需求强制退出或许持续等候。

ANR 存在的的原因是咱们不能由于一个程序呈现问题就使得整个手机无法运用。所以需求 ANR 来将错误的程序退出。而咱们对其优化则需求尽或许的削减这种情况的呈现,使得用户被打断,这是一种很不好的体会。

确诊 ANR 时需求考虑以下几种常见形式:

  1. 运用在主线程上非常缓慢地履行涉及 I/O 的操作。
  2. 运用在主线程上进行长时刻的核算。
  3. 主线程在对另一个进程进行同步 binder 调用,而后者需求很长时刻才能返回。
  4. 主线程处于堵塞状况,为产生在另一个线程上的长操作等候同步的块。
  5. 主线程在进程中或经过 binder 调用与另一个线程之间产生死锁。主线程不仅仅在等候长操作履行结束,而且处于死锁状况。

系统级优化

关于 Android 系统,Google 自身也对其系统做了许多重大的优化,这些优化使得 Android 系统许多的问题得以处理,许多运用体会变得更好。而这些优化的点,咱们能够作为往后的思路,让咱们对 APP 的优化有更宽广的思考,让咱们能发掘出更多的优化点和对其有愈加深入的思考

Android架构图

关于事务开发中,咱们许多时分都是运用到 Application 和 FrameWork 层,可是需求真正做好功能优化,咱们需求了解到许多的 中心库 Kernel 层的原理,这对咱们自身来说,也是正向的收益。

本篇四大功能优化的详解就讲到这儿,假如对你有帮助欢迎star!

参阅

VSync与屏幕撕裂 – 知乎 (zhihu.com)

屏幕撕裂及掉帧原因与处理方案_Daniel_Coder的博客-CSDN博客_屏幕撕裂

浅谈画面撕裂 – 简书 (jianshu.com)

Android 显现改写机制、VSYNC和三重缓存机制_卜大爷的博客-CSDN博客_android vsync

Service 运转在主线程_Frank_de_Boer的博客-CSDN博客_service是否在主线程中履行

View系统(下)|青训营笔记 – ()

View系统(上)|青训营笔记 – ()

Vsync 是什么 – 泪雪网 (leixue.com)

Android图形显现系统(一)_良秋的博客-CSDN博客_android显现系统

【Android 客户端专场 学习材料三】第四届字节跳动青训营 – ()

ANR | Android 开发者 | Android Developers