探析Android中的四类性能优化
作者:Yj家的孺子牛
流畅性优化
主线程模型
了解 Android 的流畅性优化之前,我们需要先了解Android的线程结构。在 Android 中,有一个主线程模型,其中所有的绘制以及交互都是在主线程中进行的,所以,当我们编写的某类代码是需要在主线程中运行的,那么这类代码必然会影响到我们的绘制等,继而影响到流畅性问题。
下图之中,展示了我们哪类代码操作代码是会影响到主线程。

-
System Events(系统事件)
例如需要关闭、开启某个页面,这些都是需要通知我们的系统的来完成的,这些就是系统事件。它会触发到主线程的耗时操作。
-
Input Events(输入事件)
输入事件并非指单纯的在输入框输入信息的事件,而是在手机上进行操作。因为手机本身可以被抽象的指代为一个输入输出的设备。在触摸屏上任意的点击都是一个输入事件,它都是在主线程中完成的
-
Application(应用事件)
我们APP的启动都是要经过应用事件,而各种生命周期的初始化相关的回调、初始化也是要经过它。例如各类启动的 SDK 都是放在
Application类中初始化的,这都是要在主线程中进行的。 -
Services(服务事件)
这一点大家也许有点疑惑,后台服务为什么会是在主线程的呢?我们不是一般新开一个线程在后台执行耗时任务的么?上述的两点其实是不矛盾的,只是我们平时的理解也许有误,认为
Services作为后台任务就是在子线程才对。但事实上,Services是运行在主线程中的,即使它是在后台执行的,而我们需要执行耗时任务的时候,再在Services中创建子线程来执行这个耗时任务 。 -
Alarm(定时事件)
定时事件中,由于它默认子线程是不安全的,主线程才是安全的,所以是需要到主线程去执行的。
而 UI绘制 虽然是在主线程中的,但是我们的代码是无法去控制它的,这是系统进行控制的。我们只能输入需要绘制什么,但是不能影响其绘制的流程。
界面更新以及卡顿
界面更新的VSync
知晓主线程模型后,我们来看一下 界面是如何刷新 的
下面的一图是介绍 Android 中的 VSync 机制,VSync 我们可以简单的理解为是一种屏幕刷新的信号,它会每隔一段时间就会刷新一次屏幕。
**垂直同步(VSync):**当屏幕从缓冲区扫描完一帧到屏幕上之后,开始扫描下一帧之前,发出的一个同步信号,该信号用来切换前缓冲区和后缓冲区。


如下图,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 时需要考虑以下几种常见模式:
- 应用在主线程上非常缓慢地执行涉及 I/O 的操作。
- 应用在主线程上进行长时间的计算。
- 主线程在对另一个进程进行同步 binder 调用,而后者需要很长时间才能返回。
- 主线程处于阻塞状态,为发生在另一个线程上的长操作等待同步的块。
- 主线程在进程中或通过 binder 调用与另一个线程之间发生死锁。主线程不只是在等待长操作执行完毕,而且处于死锁状态。
系统级优化

对于 Android 系统,Google 本身也对其系统做了很多重大的优化,这些优化使得 Android 系统很多的问题得以解决,很多使用体验变得更好。而这些优化的点,我们可以作为今后的思路,让我们对 APP 的优化有更广阔的思考,让我们能发掘出更多的优化点和对其有更加深刻的思考

对于业务开发中,我们很多时候都是使用到 Application 和 FrameWork 层,但是需要真正做好性能优化,我们需要了解到很多的 核心库 Kernel 层的原理,这对我们自身来说,也是正向的收益。
其实想要全面掌握好 Android 性能优化的话,这些知识点你必须要有所了解,如: 内存优化、网络优化、卡顿优化、存储优化……等,为了让大家一次都可以了解全,所以将其整合成名为《Android 性能优化核心知识点手册》,大家可以参考下:
《APP 性能调优进阶手册》:https://qr18.cn/FVlo89
启动优化

内存优化

UI优化

网络优化

Bitmap优化与图片压缩优化

多线程并发优化与数据传输效率优化

体积包优化

《Android 性能调优核心笔记汇总》:https://qr18.cn/FVlo89

《Android 性能监控框架》:https://qr18.cn/FVlo89

相关文章:
探析Android中的四类性能优化
作者:Yj家的孺子牛 流畅性优化 主线程模型 了解 Android 的流畅性优化之前,我们需要先了解Android的线程结构。在 Android 中,有一个主线程模型,其中所有的绘制以及交互都是在主线程中进行的,所以,当我们…...
ubuntu18.04 安装编译zlmediakit
参考http://www.cherrylord.cn/archives/zlmediakit 1、获取代码 #国内用户推荐从同步镜像网站gitee下载 git clone --depth 1 https://gitee.com/xia-chu/ZLMediaKit cd ZLMediaKit #千万不要忘记执行这句命令 git submodule update --init#国内用户推荐…...
C++ -5- 内存管理
文章目录 C语言和C内存管理的区别示例1. C/C 中程序内存区域划分2. C中动态内存管理3.operator new 与 operator delete 函数4.new 和 delete 的实现原理5.定位new表达式 C语言和C内存管理的区别示例 //C语言: struct SListNode {int data;struct SListNode* next; …...
(Linux)在Ubuntu系统中添加新用户并授予root权限
向Ubuntu系统中添加新用户并为其授予root权限的步骤如下: 打开终端Terminal 输入命令: sudo su - 以 root 身份登录. 注: sudo su : 切换root身份, 不携带当前用户环境变量 sudo su - : 切换root身份, 携带当前用户环境变量 输入命令: adduser username 向Ubuntu系统中添…...
AttributeError: ‘ChatGLMModel‘ object has no attribute ‘prefix_encoder‘
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...
Huggingface的GenerationConfig 中的top_k与top_p详细解读
Huggingface的GenerationConfig 中的top_k与top_p详细解读 Top_kTop_p联合共用 Top_k top-k是指只保留概率最高的前k个单词,然后基于剩余单词的概率进行归一化,从中随机抽取一个单词作为最终输出。这种方法可以限制输出序列的长度,并仍然保持…...
学生信息管理系统简易版(文件读写操作)
功能模块 具体功能如下: 添加学生信息修改学生信息(按学号)排序(分别按总分升序、降序、以及按姓名升序)查找学生(按学号)删除学生查看所有学生信息 数据结构体设计 本表设计一个学生信息的结…...
C/C++每日一练(20230426)
目录 1. 不喜欢带钱的小C 🌟🌟 2. 数组排序 ※ 3. 超级素数 ※ 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 不喜欢带钱的小C 小C不喜欢带钱,…...
halcon灰度积分投影/垂直积分投影
简介:关于灰度投影积分可以用到的场合很多,例如分割字符,分割尺子上的刻度等,适用于有规律的变化这些内容的检测。本文复现了论文《基于深度学习和灰度纹理特征的铁路接触网绝缘子状态检测》中灰度积分投影实现了对绝缘子缺陷位置的检测。见(图1)灰度积分垂直方向投影获得…...
Unity打包的apk在安卓4.4.2盒子上碰到的问题
项目场景: Unity开发的项目需要在安卓4.4.2盒子上运行。 问题描述 1、会出"从顶部向下滑动即可退出全屏模式。"的弹框,这是android4.4的一个特性,叫做沉浸模式(Full-screen Immersive Mode),当app启用该模…...
docker的简单使用(centos7中为例)
安装: yum -y install docker 启动: service start docker 搜索镜像: docker search centos:7.9 下载镜像: docker pull docker.io/18703283952/mycentos 查看所有镜像: docker images 启动并进入镜像:…...
Stable Diffusion人工智能图像合成
AI 图像生成大有来头。新发布的开源图像合成模型称为Stable Diffusion,它允许任何拥有 PC 和像样的 GPU 的人想象出他们能想象到的几乎任何视觉现实。它几乎可以模仿任何视觉风格,如果你给它输入一个描述性的短语,结果就会像魔术一样出现在你…...
【Java EE】-CSS详解
作者:学Java的冬瓜 博客主页:☀冬瓜的主页🌙 专栏:【JavaEE】 分享: 且视他人如盏盏鬼火,大胆地去走你的道路。——史铁生《病隙碎笔》 主要内容:CSS引入html的三种方式,CSS八大选择器ÿ…...
C#_语言简介
目录 1. C# 简介 2. Visual Studio 窗口界面显示 1. C# 简介 什么是程序? 程序(Program)简单来说就是: 计算机是无法听懂我们人类的语言的,也可以说我们通过我们日常交流的语言是无法控制计算机的,计算机…...
【Python_Opencv图像处理框架】直方图与傅里叶变换
写在前面 本篇文章是opencv学习的第五篇文章,主要讲解了直方图与傅里叶变换的有关操作,作为初学者,我尽己所能,但仍会存在疏漏的地方,希望各位看官不吝指正🥰 写在中间 一、直方图 ( 1 &…...
Know-Evolve: Deep Temporal Reasoning for Dynamic Knowledge Graphs
Know-Evolve: Deep Temporal Reasoning for Dynamic Knowledge Graphs Rakshit Trivedi 1 Hanjun Dai 1 Yichen Wang 1 Le Song 1 知识背景 Temporal Knowledge Graph : facts occur,recur or evolve over time in these graphs,and each edge in the graphs have temporal …...
电脑高效率工作、学习工具软件推荐
本文介绍在学习、工作时,实测很好用、明显提高工作效率的几个免费电脑软件与小工具。 1 Microsoft To Do 官方网站:https://todo.microsoft.com/tasks/ Microsoft To Do是一款由Microsoft公司开发的待办事项管理应用程序。它提供了一个简单易用的界面&a…...
Java8新特性函数式编程 - Lambda、Stream流、Optional
1.Lambda表达式 1.1 概述 Lambda是JDK8中一个语法糖。他可以对某些匿名内部类的写法进行简化。它是函数式编程思想的一个重要体现。让我们不用关注是什么对象。而是更关注我们对数据进行了什么操作。 1.2 核心原则 可推导可省略 1.3 基本格式 (参数列表)->{代码}例一…...
AutoGPT安装教程
最近安装AutoGPT时遇到了一些问题,写下这篇文章记录一下 1 下载AutoGPT AutoGPT链接:https://github.com/Significant-Gravitas/Auto-GPT/tree/v0.2.2 下载AutoGPT 推荐下载stable 版本 2 申请openai 的api key 获取api的key,这里就不介…...
轻量级服务器nginx:负载均衡
负载均衡就是让每个设备,以同样的概率,处理用户对于服务器的任务请求,默认采用的负载调度策略就是轮流询问,Nginx作为反向代理服务器安装在服务端,Nginx的功能就是把请求转发给后面的应用服务器. 这里写目录标题 一 负…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
