想要深入学习Android性能优化?看完这篇直接让你一步到位
wptr33 2025-04-11 08:28 42 浏览
Android性能优化
Android中的性能优化基本上可以分为以下几个方面:
● 布局优化
● 网络优化
● 内存优化
● 卡顿优化
● 启动优化
布局优化
Android的布局管理器本身就是个UI组件; 所有的布局管理器都是ViewGroup的子类,而ViewGroup是View的子类,所以布局管理器可以当成普通的UI组件使用,也可以作为容器类使用,可以调用多个重载addView()向布局管理器中添加组件,并且布局管理器可以互相嵌套;当然不推荐过多的嵌套 (兼容低端机型,最好不要超过5层)
布局层级管理
让咱们一起了解一下每当系统绘制一个布局时,都会发生一些什么; 这一过程由两个步骤完成:
绘制(Measurement)
● 根布局测量自身
● 根布局要求它内部所有子组件测量自身
● 所有自布局都需要让它们内部的子组件完成这样的操作,直到遍历完视图层级中所有的View
摆放(Positioning)
● 当布局中所有的View都完成了测量,根布局则开始将它们摆放到合适的位置
● 所有子布局都需要做相同的事情,直到遍历完视图层级中所有的View
当某个View的属性发生变化(如:TextView内容变化或ImageView图像发生变化),View自身会调用View.invalidate()方法(必须从 UI 线程调用),自底向上传播该请求,直到根布局(根布局会计算出需要重绘的区域,进而对整个布局层级中需要重绘的部分进行重绘)
布局层级越复杂,UI加载的速度就越慢。因此,在编写布局的时候,尽可能地扁平化是非常重要的
FrameLayout和TableLayout有各自的特殊用途,LinearLayout 和 RelativeLayout 是可以互换的,ConstraintLayout和RelativeLayout类似
也就是说,在编写布局时,可以选择其中一种,也可以用不同的方式来编写布局
网络优化
网络优化的三个要点
多维
● 网络优化应该是多维的,一般情况下,一谈到网络优化,大部分人首先想到的就是流量消耗,但是实际上流量消耗多少只是网络优化的其中一个维度
● 只对流量消耗一个维度进行优化是不够的,甚至有的团队即便在流量优化上也没有做好,比如对于网络流量的消耗统计不够全面和精确
精准
● 在做网络流量统计时,我们要做精准度量,如果只是获取了具体消耗了多少的值,对于我们定位和解决问题是没有太大的帮助,因为这个值只能表明用户用了多少流量
● 如果线上用户反馈 App 消耗流量较多,但是我们不知道这个用户总共使用了 App 多长时间的话,那就不好定位问题所在,如果用户使用 App 的时间比较长,那消耗流量多一些很可能是正常的
● 又比如用户反馈 App 在后台消耗流量比较多,但是我们只统计了整体的值,那就无法断定 App 在后台运行时到底消耗了多少流量
监控
● 针对网络优化,我们应该建设全面且完善的网络监控体系,不能只监控一个指标,假如只监控网络请求成功率,那我们就只能知道用户大概的网络使用情况,这种粗粒度的监控没办法帮助我们找出并解决问题的根源
● 比如线上用户使用了某个功能使用了 1000 次,然后出现了 1 次异常,而且用户点击重试后就恢复正常了
● 这样单从数据上来看的话,网络请求的成功率还是比较高的,但是只通过成功率一个值是无法知道这一次异常出现的原因,也就无法避免后续出现这类异常
网络优化的两个维度
流量维度
● 流量维度也就是 App 在一段时间内流量消耗的精准度量
● 流量消耗大不仅对用户有影响,对公司的运营成本也有影响,比如带宽、服务器数量、CDN 等方面的开支,而且网络请求密集对手机耗电量也有一定的影响
● 在流量维度上,我们要做到区分类型、监控异常、上报日志
区分类型
● 我们不仅要知道用户在某个时间段内的具体流量消耗,还要知道用户在不同网络类型(流量、WiFi)下的流量消耗、区分 App 在前台和在后台时的流量消耗
● 只有积累了不同维度的数据,才能快速断定和解决问题
监控异常
对于流量统计,我们不仅要知道用户的流量消耗均值,还要知道线上用户消耗流量的异常率。
这里的异常分为三种:
● 流量消耗过多
● 请求次数过多
● 下载文件过大
这三个都是我们要注意的异常
上报日志
● 最理想的情况,就是我们对所有的网络请求,在本地都有一个完整的监控,每一个请求的 Request 和 Response 相关的所有信息都全部记录下来
● 服务端可以下发指令控制客户端上传这些数据,客户端也可以在相关数据超过阈值后主动上报
质量维度
网络请求的质量也非常关键,它直接对应了用户的真实体验,如果网络请求速度慢或请求成功率比较低,都会导致不好的用户体验
对于网络请求质量的监控,可以从下面几个维度进行区分,以便后续能快速定位和解决问题
● 请求时长
● 请求成功率
● 失败率
● Top 失败接口
网络优化的两个误区
只关注流量
● 只关注流量消耗,忽视了其他维度
忽略个体数据
● 还有就是做网络监控时只关注均值和整体的数据,忽略了个体的数据
● 比如前面提到的请求成功率的例子,从整体上来看成功率非常高,但是这种数据无法帮助我们改善单次请求
● 做内存优化的目的是降低OOM率、减少卡顿、增加应用存活时间
内存优化
降低OOM率
● 做内存优化的一个常见原因是为了降低OOM率 申请内存过多而没有及时释放,常常就会导致OOM 引起OOM的原因有多种,在后面我们再细谈
减少卡顿
● Android中造成界面卡顿的原因有很多种,其中一种就是由内存问题引起的. 内存问题之所以会影响到界面流畅度,是因为垃圾回收. 在GC时,所有线程都要停止,包括主线程.当GC和绘制界面的操作同时触发时,绘制的执行就会被搁置,导致掉帧,也就是界面卡顿
增加应用存活时间
● Android会按照特定的机制清理进程,清理进程时优先会考虑清理后台进程,如果某个应用在后台运行并且占用的内存更多,就会被优先清理掉 我们通常希望App能尽量存活的久一点,所以内存不再使用时应该尽快释放
导致卡顿的因素
● 硬件因素:CPU、RAM、ROM、HeapSize、SDK Version
● 软件因素:UI渲染相关、UI线程操作相关
卡顿优化
如何定义发生了卡顿现象:
● 如果App的FPS平均值小于30,最小值小于24,即表明应用发生了卡顿
● 线下很难复现,与发生场景强相关(所以需要我们去做卡顿监控,收集现场信息)
CPU相关知识
● 现在最新的主流机型都使用了多级能效的CPU架构(即多核分层架构)
● 从 CPU 到 GPU 再到 AI 芯片NPU,随着手机 CPU 整体性能的飞跃, 我们可以充分利用移动端的计算能力来降低高昂的服务器成本
● 评价一个 CPU 的性能,需要看主频、核心数、缓存等参数,具体表现出来的是计算能力和指令执行能力,也就是每秒执行的浮点计算数和每秒执行的指令数
● 造成卡顿的原因很多(涉及到代码、内存、绘制、IO、CPU等),最终都反映到 CPU 时间上; CPU时间 可以分为用户时间和系统时间:
● 用户时间:执行用户态应用程序代码所消耗的时间
● 系统时间:执行内核态系统调用所消耗的时间,包括 I/|O、锁、中断以及其他系统调用的时间
CPU相关的三类问题
CPU资源冗余使用:
● 算法效率低
● 没使用缓存
● 计算时使用的基本类型不对(如int足够却用long,运算压力多出4倍)
CPU资源争抢:
● 抢主线程的CPU资源
● 抢音视频的CPU资源
● 编解码本身会消耗大量的CPU资源,并且其对于解码的速度是有硬性要求的,如果达不到就可能产生播放流畅度的问题
采取两种方式去优化:
● 尽量排除非核心业务的消耗
● 优化自身的性能消耗,把CPU负载转化为GPU负载,如使用renderscript来处理视频中的影像信息
大家平等,互相抢(三个和尚没水喝)
CPU资源利用率低:
● 有磁盘和网络I/O,还有锁操作、sleep等等, 对于锁的优化,通常是尽可能地缩减锁的范围
启动优化
网上流行一种说法,就是8秒定律,意思是说,如果用户在打开一个页面,在8秒的时间内还没有打开,那么用户大概的会放弃掉,意味着一个用户的流失。从这里就可以看出,启动优化的重要性了
启动的分类
冷启动
先来看看冷启动的流程图:
从图中可以看出,APP启动的过程是:ActivityManagerProxy 通过IPC来调用AMS(ActivityManagerService),AMS通过IPC启动一个APP进程,ApplicationThread通过反射来创建Application并且绑定,最后通过ActivityThread来控制activity的生命周期,在相关页面的生命周期中通过ViewRootImpl来对view的实现;从而完成应用的启动
热启动
热启动的速度是最快的,它就是进程从后台切换到前台的一个过程。
温启动
温启动只会重新走一遍页面的生命周期,但是对于进程,application不会重新在创建。
优化方向
上面介绍了启动的几种方式可以看出,我们针对启动优化,基本只是优化冷启动就可以了。但是从冷启动的启动流程中很多都是系统做的,我们没有办法操控。我们能做的,就是application的生命周期和activity的生命周期这部分,启动优化往往就是从这两块入手。
优化总结
性能优化是我们进阶的必经之路
所以,我们必须要会,至于“会”到什么程度,就要看个人理解了
其实,上面介绍的只是性能问题的冰山一角,真正的优化,我们是在项目中总结出来的;但,我们不能一味的追求优化,就例如我,现在只是在进行优化的总结,而对于真正的实行,并没有开始,因为,优化是有风险的,一个不小心,整个项目都可能炸了
所以这就需要你的经验,以及各种总结,在改进行优化的地方先进行优化,看看效果如何,例如,UI的优化以及代码的优化
可以先拿一些网上的开源项目进行优化等等
也可以私信发送 “笔记“ 或 “进阶” 获取更多 Android学习笔记
相关推荐
- MySQL进阶五之自动读写分离mysql-proxy
-
自动读写分离目前,大量现网用户的业务场景中存在读多写少、业务负载无法预测等情况,在有大量读请求的应用场景下,单个实例可能无法承受读取压力,甚至会对业务产生影响。为了实现读取能力的弹性扩展,分担数据库压...
- 3分钟短文 | Laravel SQL筛选两个日期之间的记录,怎么写?
-
引言今天说一个细分的需求,在模型中,或者使用laravel提供的EloquentORM功能,构造查询语句时,返回位于两个指定的日期之间的条目。应该怎么写?本文通过几个例子,为大家梳理一下。学习时...
- 一文由浅入深带你完全掌握MySQL的锁机制原理与应用
-
本文将跟大家聊聊InnoDB的锁。本文比较长,包括一条SQL是如何加锁的,一些加锁规则、如何分析和解决死锁问题等内容,建议耐心读完,肯定对大家有帮助的。为什么需要加锁呢?...
- 验证Mysql中联合索引的最左匹配原则
-
后端面试中一定是必问mysql的,在以往的面试中好几个面试官都反馈我Mysql基础不行,今天来着重复习一下自己的弱点知识。在Mysql调优中索引优化又是非常重要的方法,不管公司的大小只要后端项目中用到...
- MySQL索引解析(联合索引/最左前缀/覆盖索引/索引下推)
-
目录1.索引基础...
- 你会看 MySQL 的执行计划(EXPLAIN)吗?
-
SQL执行太慢怎么办?我们通常会使用EXPLAIN命令来查看SQL的执行计划,然后根据执行计划找出问题所在并进行优化。用法简介...
- MySQL 从入门到精通(四)之索引结构
-
索引概述索引(index),是帮助MySQL高效获取数据的数据结构(有序),在数据之外,数据库系统还维护者满足特定查询算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构...
- mysql总结——面试中最常问到的知识点
-
mysql作为开源数据库中的榜一大哥,一直是面试官们考察的重中之重。今天,我们来总结一下mysql的知识点,供大家复习参照,看完这些知识点,再加上一些边角细节,基本上能够应付大多mysql相关面试了(...
- mysql总结——面试中最常问到的知识点(2)
-
首先我们回顾一下上篇内容,主要复习了索引,事务,锁,以及SQL优化的工具。本篇文章接着写后面的内容。性能优化索引优化,SQL中索引的相关优化主要有以下几个方面:最好是全匹配。如果是联合索引的话,遵循最...
- MySQL基础全知全解!超详细无废话!轻松上手~
-
本期内容提醒:全篇2300+字,篇幅较长,可搭配饭菜一同“食”用,全篇无废话(除了这句),干货满满,可收藏供后期反复观看。注:MySQL中语法不区分大小写,本篇中...
- 深入剖析 MySQL 中的锁机制原理_mysql 锁详解
-
在互联网软件开发领域,MySQL作为一款广泛应用的关系型数据库管理系统,其锁机制在保障数据一致性和实现并发控制方面扮演着举足轻重的角色。对于互联网软件开发人员而言,深入理解MySQL的锁机制原理...
- Java 与 MySQL 性能优化:MySQL分区表设计与性能优化全解析
-
引言在数据库管理领域,随着数据量的不断增长,如何高效地管理和操作数据成为了一个关键问题。MySQL分区表作为一种有效的数据管理技术,能够将大型表划分为多个更小、更易管理的分区,从而提升数据库的性能和可...
- MySQL基础篇:DQL数据查询操作_mysql 查
-
一、基础查询DQL基础查询语法SELECT字段列表FROM表名列表WHERE条件列表GROUPBY分组字段列表HAVING分组后条件列表ORDERBY排序字段列表LIMIT...
- MySql:索引的基本使用_mysql索引的使用和原理
-
一、索引基础概念1.什么是索引?索引是数据库表的特殊数据结构(通常是B+树),用于...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
程序员的开源月刊《HelloGitHub》第 71 期
-
详细介绍一下Redis的Watch机制,可以利用Watch机制来做什么?
-
假如有100W个用户抢一张票,除了负载均衡办法,怎么支持高并发?
-
如何将AI助手接入微信(打开ai手机助手)
-
Java面试必考问题:什么是乐观锁与悲观锁
-
SparkSQL——DataFrame的创建与使用
-
redission YYDS spring boot redission 使用
-
一文带你了解Redis与Memcached? redis与memcached的区别
-
如何利用Redis进行事务处理呢? 如何利用redis进行事务处理呢英文
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)