探析Android中的四类性能优化(一)

简介: 在上一篇文章 初识性能优化 中我们提到我们需要从流畅性优化、资源优化、稳定性优化 和 系统级优化 这四个层面来对Android中的软件做优化。

前置知识

  • 有Android开发基础
  • 了解Android运行原理

前言

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

流畅性优化

主线程模型

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

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

1.webp.jpg

  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):**当屏幕从缓冲区扫描完一帧到屏幕上之后,开始扫描下一帧之前,发出的一个同步信号,该信号用来切换前缓冲区和后缓冲区。

1.webp.jpg

而在 Android 中,VSync 信号的回调一般会在主线程中每隔16ms执行一次,而我们通过频率计算公式来计算一下: f=1Tf=\frac{1}{T} f=T1,当 T=16msT=16msT=16ms 时候,我们可以得出 f=62.5HZf=62.5HZf=62.5HZ 这个就是我们常用的 60fps60fps60fps

在我们的视觉感知中,24fps24fps24fps 通常可以让人眼感知到线性动作了,而人能感知到不卡顿的最低帧数则为 25fps25fps25fps。在 Vsync 机制中的 60fps60fps60fps 则可以让设备呈现更加绚丽的效果,对于当下热炒的 90fps90fps90fps120fps120fps120fps 则是让感觉上更加顺滑而已,但是对于与实际和功耗的平衡,高于 60fps60fps60fps 是没有必要的。

如下图,UI Draw 会在 16ms 就执行一次,所以我们的需要让我们的绘制流程在 16ms 内执行完才不会出现卡顿问题。

1.webp.jpg

所以说,如果我们不影响界面的更新,让每次绘制流程都可以保持在16ms以下,那么就不会出现卡顿问题了。

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

  • 输入事件无法即时响应
    这类卡顿主要表现为我们滑动屏幕的时候,屏幕根本无法响应。这是由于我们在主线程中执行了一段非常耗时的、与事件无关的代码,而由于这段代码还在执行,所以输入事件根本没法执行,也没法绘制出我们的滑动效果了。
    1.webp (1).jpg
  • 输入事件立刻响应,但其耗时较长
    这类卡顿中,输入事件是立即响应的了,但是由于我们又在输入事件的分发中做了很多计算逻辑等耗时的操作,所以还是会出现卡顿。其表现出来的效果是,滑动的时候一卡一卡的,这是由于输入事件的执行超过了16ms了,导致了丢帧的问题。
    1.webp.jpg
  • UI Draw 之外需要在主线程中执行的任务耗时长
    我们知道,主线程中不单只有 UI 的绘制任务,还有其他的例如 Application 任务也是需要放置在主线程中执行的。这些任务如果不做处理,也一股脑的放置在主线程中执行,那么也会导致其占用时间过长,使得 APP 出现丢帧的问题。
    1.webp.jpg

解决卡顿问题

我们现已经知道了三大类卡顿的原因,其归结来说的原因就是主线程中出现了不必要的耗时操作,导致最后主线程的UI绘制出现阻塞或者溢出。那么我们解决卡顿、做流畅性优化的方法也是很明确了,那就是让主线程尽量只做交互(Input Event)以及刷新(UI Draw)。当然很多需要在主线程中的代码是无法避免的,但是我们尽量使其缩小,让所有的耗时代码都在子线程中运行,这样子使得其减少丢帧,能够更加的连贯顺滑。

1.webp.jpg

没有VSync会怎么样?

上述讲到了 VSync 的作用以及卡顿的原因和处理,我们知道 VSync 信号可以用于同步刷新页面。那若是没有 VSync 信号,我们的页面会出现什么样的问题?

其实会出现画面撕裂。画面撕裂是什么呢?如下图中红色框中的图面,与上边出现了撕裂,这种就是画面撕裂。其出现的原因是上一帧的页面还在绘制中,下一帧页面就继续占用资源绘制了,所以会出现几帧的页面同时绘制在一个页面中,出现了画面撕裂感。

1.webp.jpg

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

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

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

所以说,解决画面撕裂的核心是决定好数据的交换时机(绘制时机)由谁来控制。在绘制中,不应该是 CPU 处理写入之后就立即绘制,而应该是由屏幕渲染完一帧之后才去绘制绘制下一帧。然而屏幕不是控制器,它无法控制什么时候进行绘制,但是它可以传递 VSync 信号给 Android 系统,借助 VSync 信号,Android 就可以让 CPU 在新的一帧开始的时候立即处理显示问题了。

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

1.webp.jpg

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



相关文章
|
29天前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
117 4
|
2月前
|
算法 数据处理 Android开发
掌握安卓性能优化的秘诀:电池寿命与运行效率的提升
【10月更文挑战第6天】 本文深入探讨了安卓应用开发中的性能优化技巧,重点分析了影响电池寿命和运行效率的关键因素,并提供了针对性的优化策略。通过代码优化、资源管理、后台任务处理等方法,开发者可以显著提升应用的续航能力和流畅度。同时,结合具体案例,展示了如何在实际开发中应用这些技巧,确保应用在各种场景下都能保持高效运行。本文旨在为安卓开发者提供实用的性能优化指导,助力其打造更优质的应用体验。
70 2
|
21天前
|
网络协议 Linux Android开发
深入探索Android系统架构与性能优化
本文旨在为读者提供一个全面的视角,以理解Android系统的架构及其关键组件。我们将探讨Android的发展历程、核心特性以及如何通过有效的策略来提升应用的性能和用户体验。本文不包含常规的技术细节,而是聚焦于系统架构层面的深入分析,以及针对开发者的实际优化建议。
35 1
|
1月前
|
Android开发 开发者
Android性能优化——内存管理的艺术
Android性能优化——内存管理的艺术
|
1月前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
38 5
|
1月前
|
缓存 数据库 Android开发
安卓开发中的性能优化技巧
【10月更文挑战第29天】在移动应用的海洋中,性能是船只能否破浪前行的关键。本文将深入探讨安卓开发中的性能优化策略,从代码层面到系统层面,揭示如何让应用运行得更快、更流畅。我们将以实际案例和最佳实践为灯塔,引领开发者避开性能瓶颈的暗礁。
57 3
|
2月前
|
存储 缓存 网络协议
5个Android性能优化相关的深度面试题
本文涵盖五个Android面试题及其解答,包括优化应用启动速度、内存泄漏的检测与解决、UI渲染性能优化、减少内存抖动和内存溢出、优化网络请求性能。每个问题都提供了详细的解答和示例代码。
31 2
|
2月前
|
监控 测试技术 Android开发
掌握安卓性能优化的关键策略
【10月更文挑战第7天】 在移动应用开发领域,性能优化是一项至关重要的任务。本文将探讨安卓应用性能优化的重要性、关键策略以及实际操作建议,帮助开发者提升应用的用户体验和竞争力。通过深入浅出的方式,我们将从背景介绍到具体实践,全面解析安卓性能优化的各个维度。
|
3月前
|
存储 Java 编译器
🔍深入Android底层,揭秘JVM与ART的奥秘,性能优化新视角!🔬
【9月更文挑战第12天】在Android开发领域,深入了解其底层机制对提升应用性能至关重要。本文详述了从早期Dalvik虚拟机到现今Android Runtime(ART)的演变过程,揭示了ART通过预编译技术实现更快启动速度和更高执行效率的奥秘。文中还介绍了ART的编译器与运行时环境,并提出了减少DEX文件数量、优化代码结构及合理管理内存等多种性能优化策略。通过掌握这些知识,开发者可以从全新的角度提升应用性能。
79 11
|
3月前
|
图形学 iOS开发 Android开发
从Unity开发到移动平台制胜攻略:全面解析iOS与Android应用发布流程,助你轻松掌握跨平台发布技巧,打造爆款手游不是梦——性能优化、广告集成与内购设置全包含
【8月更文挑战第31天】本书详细介绍了如何在Unity中设置项目以适应移动设备,涵盖性能优化、集成广告及内购功能等关键步骤。通过具体示例和代码片段,指导读者完成iOS和Android应用的打包与发布,确保应用顺利上线并获得成功。无论是性能调整还是平台特定的操作,本书均提供了全面的解决方案。
160 0