Android 性能优化——APP启动优化
一、APP启动流程
首先在《Android系统和APP启动流程》中我们介绍了 APP 的启动流程,但都是 FW 层的流程,这里我们主要分析一下在 APP 中的启动流程。要了解 APP 层的启动流程,首先要了解 APP 启动的分类。
1、启动分类
冷启动
应用从头开始启动,即应用的首次启动。需要做大量的工做,耗费的时间最多。
热启动
当活动有驻留在内存中,系统只是把该活动放到前台,无需重复对象初始化、布局扩充和呈现。例如按了home键,相对于冷启动,开销较低。
温启动
用户退出应用程序,随后又从新启动,可是活动的进程是有驻留在后台的。例如按了back键退出应用。
2、生命周期
冷启动
对于冷启动的耗时计算比较复杂,除了 Activity 本身的生命周期外,还要考虑 Application 中
onCreate 的耗时操作。所以对于冷启动来说,一般从进程创建(即
Application 的attachBaseContext 方法)开始计时,到
完成视图的第一次绘制(即 Activity 的 onWindowFocusChanged 方法)停止计时。
冷启动 Activity 生命周期:
onCreate() -> onStart() -> onResume() -> onWindowFocusChanged()
热启动
相比于冷启动,热启动省去了 Application 的初始化,以及 Activity 的 onCreate。热启动生命周期:
Home:onPause() -> onStop()
热启动:onStart() -> onResume()
温启动
温启动生命周期:
Back:onPause() -> onStop() -> onDestory()
热启动:onCreate() -> onStart() -> onResume()
可以看到温启动相比热启动,Activity 生命周期增加了一个 onCreate() 方法,在使用 Back 时也比 Home 多执行一个 onDestory()。
二、启动时间统计
1、埋点统计
根据上面的生命周期,在不同方法中打印当前时间,通过查看 Log 计算不通启动方式的启动耗时。
2、查找Log
通过查找 Log 关键字 Displayed 查看 APP 入口信息,即包含启动时间。
adb命令
adb logcat | grep "Displayed"
结果输出
I/ActivityManager( 384): Displayed com.test.myapp/com.test.myapp.MainActivity: 1734 ms (total 1734 ms)
3、adb命令统计
adb shell am start -W
包名/启动类的全限定名
实际使用
adb shell am start -W com.test.myapp/com.test.myapp.MainActivity
冷启动需要杀掉最近任务进程,再使用上面的命令。热启动需要 Home 键退出应用后使用上面命令。
结果输出
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.test.myapp/.MainActivity }
Warning: Activity not started, its current task has been brought to the front
Status: ok
LaunchState: HOT
Activity: com.test.myapp/.MainActivity
ThisTime: 79
TotalTime: 79
WaitTime: 82
Complete
LaunchState:启动方式 COLD(冷启动)、 HOT(热启动)和 WARM(温启动)。
ThisTime:启动多个 Activity 的最后一个 Activity 的启动耗时。
TotalTime:启动多个 Activity 总耗时,包括新进程的启动和 Activity 的启动。也就是说,开发者一般只要关心 TotalTime 即可,这个时间才是自己应用真正启动的耗时。
WaitTime:应用进程的创建过程 + TotalTime,就是总的耗时,包括前一个应用 Activity pause 的时间和新应用启动的时间。
如果只关心某个应用自身启动耗时,参考TotalTime;如果关心系统启动应用耗时,参考WaitTime;如果关心应用有界面Activity启动耗时,参考ThisTime。
多次测试
adb shell am start -S -R 10 -W com.test.myapp/com.test.myapp.MainActivity
其中 -S 表示每次启动前先强行停止,-R表示重复测试次数,注意反斜杠、包名、类名。所以可以通过 -S 设置冷/热启动。
三、方法耗时统计
traceview 统计可以用代码统计。也可以用 Android Studio自带的 cup profiler 来统计。
1、Debug Trace
@Override
public void onCreate() {super.onCreate();Debug.startMethodTracing("main_trace");……Debug.stopMethodTracing();
}
生成文件路径:storage/emulated/0/Android/data/packagename/files/main_trace。
然后直接将该文件拖入到 Android Studio 中,就能看到对应方法执行的时长,从而进行相关的优化,如是否可以在异步线程操作该方法或者考虑懒加载的方式,根据自己的业务找到合适的方法。
2、CPU Profiler
Profiler 是 Android Studio 内置的工具。如下配置:
1)run -> edit configurations;
2)勾选start recording a method trace on startup;
3)从菜单中选择cpu记录配置(profiling菜单下勾选两个复选框);
4)apply --> profile模式部署。
详细使用参考:Android app的启动优化总结
3、systrace
@Override
public void onCreate() {super.onCreate();Trace.beginSection("Launcher");……Trace.endSection();
}
命令行终端进入如下目录:
/Users/tian/Library/Android/sdk/platform-tools/systrace
输入如下命令进入监听状态:
python systrace.py -o main_trace sched freq idle am wm gfx view binder_driver hal dalvik camera input res
此时运行代码,完成之后在命令行窗口按 Enter
键结束监听,然后会生成目标文件 main_trace,同样使用 Android Studio 的 Profiler 工具进行分析。
三、优化策略
1、优化onCreate, onStart,onResume函数
由于许多内容在 Activity 的 UI 初始化和生命周期中需要用到,所以大部分 Activity 中的成员需要在 onCreate 中通过 new 的方式赋值。这就要求 new 的类的构造函数应该尽可能简单,不要有耗时操作,以便快速执行。
不要在这些函数中 new 暂时用不到的内容,比如一些提醒的 dialog,可以在需要提醒的地方再去创建。
2、优化布局文件
减少UI的布局嵌套层数,从而减少 layout 时间。 简化XML布局,界面布局时,层次越多,加载的时间就越长。因此应该尽可能的减少布局层次。如果实在层次太多并且无法简化,建议不使用XML布局,直接在代码中进行布局。
判断嵌套布局是否可以优化的方法:
1)借助工具Hierarchy Viewer,可以看到layout比较耗时的节点。
2)直接review xml布局文件。
布局优化方案:
1)尽量使用 ConstraintLayout 和 RelativeLayout 替换 LinearLayout。
2)尽量为所有分辨率创建资源,减少不必要的硬件缩放,这会降低UI的绘制速度。
3)首次不需要显示的节点,尽量设置为GONE。
3、优化draw过程
去掉不必要的背景,比如如果子节点和父节点size一样,那么父节点的background可以不设或者设为null。
尽可能少用或者不用高质量图片,以提高运行效率。
4、优化数据访问
有些属性需要在 onCreate 就获取,而这些属性保存在 ContentProvider 中。可以从下面两方面进行优化:
1)少用 cursor.getColumnIndex。可以在建表的时候用 static 变量记住某列的 index,直接调用相应index而不是每次查询。
2)查询时返回更少的结果集及更少的字段。只返回需要的字段和结果集,更多的结果集和字段会消耗更多的时间及内存。
5、优化自定义控件或UI部件
自定义控件和UI部件,不管这些控件是否支持 xml 化,实现它们的代码质量很重要,要尽可能简化它们的构造过程。
6、代码方面的优化
1)使用缓存。尽量将需要频繁访问或访问一次消耗较大的数据存储在缓存中。
2)使用多线程。比较耗时的过程,尽可能的使用异步加载。避免UI主线程阻塞,发生长时间不响应。
3)只需要获取图片的高宽时,可以设置 InJustDecodeBounds 为 true。这样就不会去 decode 图片,减少了图片解析的时间。
4)判断语句如果较多时,尽量使用 switch..case..,而不是使用 if..else..。因为 if..else.. 是从上到下进行判断,而 switch..case.. 有对判断条件进行优化。
5)for() 循环中有 if() 判断,考虑实现为将 if() 判断语句放在 for() 语句外面,减少判断次数,for 语句可以快速执行。
6)String的拼接尽量使用io流。
7)数据类型和数据结构的选择。比如:hash 系列数据结构查询速度更优,ArrayList 存储有序元素。
7、延迟执行
对于 onCreate, onStart,onResume 函数中的数据或变量初始化,不着急使用的可以放到使用时在进行初始化,或者放到子线程中处理。
8、空闲时间利用
合理利用程序的空闲时间,等待页面都完全渲染完毕之后再执行。例如:使用IdleHandler
,具体使用如下:
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {@Overridepublic boolean queueIdle() {// 执行你的任务return false;}
});
空闲时执行多个任务:
public class DelayTaskQueue {private final Queue<Runnable> mDelayTasks = new LinkedList<>();private final MessageQueue.IdleHandler mIdleHandler = () -> {if (mDelayTasks.size() > 0) {Runnable task = mDelayTasks.poll();if (task != null) {task.run();}}// mDelayTasks非空时返回ture表示下次继续执行,为空时返回false系统会移除该IdleHandler不再执行return !mDelayTasks.isEmpty();};public DelayTaskQueue addTask(Runnable task) {mDelayTasks.add(task);return this;}public void start() {Looper.myQueue().addIdleHandler(mIdleHandler);}
}
9、锁优化
锁是我们解决并发的重要手段,但是如果滥用锁的话,很可能造成执行效率下降,更严重的可能造成死锁等无法挽回的场景。
当我们需要处理高并发的场景时,同步调用尤其需要考量锁的性能损耗:
1)能用无锁数据结构,就不要用锁。
2)缩小锁的范围。能锁区块,就不要锁住方法体;能用对象锁,就不要用类锁。
10、内存优化
内存优化的核心是避免内存抖动。不合理的内存分配、内存泄漏、对象的频繁创建和销毁,都会导致内存发生抖动,最终导致系统的频繁 GC。
1)解决应用的内存泄漏问题。这里我们可以使用LeakCanary 或者 Android Profile 等工具来检查我们查询可能存在的内存泄漏。平时编码应当注意避免内存泄漏。
2)如避免全局静态变量和常量、单例持有资源对象(Activity,Fragment,View等),资源使用完立即释放或者recycle(回收)等。
3)避免创建大内存对象,频繁创建和释放对象(尤其是在循环体内),频繁创建的对象需要考虑复用或者使用缓存。
4)加载图片可以适当降低图片质量,小图标尽量使用SVG,大图/复杂的图片考虑使用webp。尽量使用图片加载框架,如glide,这些框架都会帮我们进行加载优化。
5)避免大量bitmap的绘制。
6)避免在自定义View的onMeasure、onLayout和onDraw中创建对象。
7)使用 SpareArray、ArrayMap 替代 HashMap。
8)避免进行大量的字符串操作,特别是序列化和反序列化。不要使用+(加号)进行字符串拼接。
9)使用线程池(可设置适当的最大线程池数)执行线程任务,避免大量Thread的创建及泄漏。
11、线程优化
当我们创建一个线程时,需要向系统申请资源,分配内存空间,这是一笔不小的开销,所以我们平时开发的过程中都不会直接操作线程,而是选择使用线程池来执行任务。所以线程优化的本质是对线程池的优化。
12、IO优化
IO优化的核心是减少IO次数。
网络请求优化
1)避免不必要的网络请求。对于那些非必要执行的网络请求,可以延时请求或者使用缓存。
2)对于需要进行多次串行网络请求的接口进行优化整合,控制好请求接口的粒度。比如后台有获取用户信息的接口、获取用户推荐信息的接口、获取用户账户信息的接口。这三个接口都是必要的接口,且存在先后关系。如果依次进行三次请求,那么时间基本上都花在网络传输上,尤其是在网络不稳定的情况下耗时尤为明显。但如果将这三个接口整合为获取用户的启动(初始化)信息,这样数据在网络中传输的时间就会大大节省,同时也能提高接口的稳定性。
磁盘IO优化
1)避免不必要的磁盘IO操作。这里的磁盘IO包括:文件读写、数据库(sqlite)读写和SharePreference等。
2)对于数据加载,选择合适的数据结构。可以选择支持随机读写、延时解析的数据存储结构以替代 SharePreference。
3)避免程序执行出现大量的序列化和反序列化(会造成大量的对象创建)。
参考:Android APP启动速度优化
相关文章:
Android 性能优化——APP启动优化
一、APP启动流程 首先在《Android系统和APP启动流程》中我们介绍了 APP 的启动流程,但都是 FW 层的流程,这里我们主要分析一下在 APP 中的启动流程。要了解 APP 层的启动流程,首先要了解 APP 启动的分类。 1、启动分类 冷启动 应用从头开始…...

计算机网络:TCP篇
计网tcp部分面试总结 tcp报文格式: 序列号:通过SYN传给接收端,当SYN为1,表示请求建立连接,且设置序列号初值,后面没法送一次数据,就累加数据大小,保证包有序。 确认应答号&#x…...
【NLP11-迁移学习】
1、了解迁移学习中的有关概念 1.1、预训练模型(pretrained model) 一般情况下预训练模型都是大型模型,具备复杂的网络结构,众多的参数量,以及在足够大的数据集下进行训练而产生的模型。在NLP领域,预训练模型往往是语…...
Android11 FallbackHome启动和关闭流程分析
Android 7.0引入了新特性:Direct Boot Mode,设备启动后进入的一个新模式,直到用户解锁(unlock)设备此阶段结束。在这个模式下,系统调用 resolveHomeActivity 找到的是FallbackHome ,而不是我们的…...
elasticsearch-java api 8 升级
es client api 升级 背景 公司项目从sring-boot2 升级到了spring-boot3 ,es的服务端也跟着升级到了es8 ,而es的客户端7和服务端8 是不兼容的, 客户端es 7使用的是: elasticsearch-rest-high-level-client es 8 升级到…...
HCIA_IP路由基础问题?
目录 1. 什么是路由?2. 什么是路由器?3. 什么是路由信息?4. 路由器信息和路由表的区别?5. 路由表的生成方式?6.直连路由生效条件是什么?7.Inloopback0是什么接口?8.最优路由选择的原则ÿ…...

(黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
(黑马出品_高级篇_01)SpringCloudRabbitMQDockerRedis搜索分布式 微服务技术——保护 今日目标1.初识Sentinel1.1.雪崩问题及解决方案1.2.服务保护技术对比1.3.Sentinel介绍和安装1.3.1.初识Sentinel1.3.2.安装Sentinel 1.…...

高架学习笔记之信息系统分类概览
目录 零、前言 一、业务处理系统(TPS) 概念 功能 特点 二、管理信息系统(MIS) 概念 功能 组成 三、决策支持系统(DSS) 概念 功能 特点 组成 1. 数据仓库 2. 数据挖掘工具 3. 决策模型 4. 可视化界面 四、专家系统(ES) 概念 特点 组成 求解过程 专家系统…...

2023新版mapinfo美化电子地图 新版2013Arcgis shp电子地图 下载
2023新版MapInfo和电子地图美化,以及2013版ArcGIS的SHP电子地图设计,是地理信息系统(GIS)领域中的两个重要话题。下面将分别对这两个主题进行描述。 样图: 链接:https://pan.baidu.com/s/1WB4AGsycyBGagVq5…...

BUUCTF-Ezsql1
1.打开靶机 打开第一个链接 2.万能密码 使用万能密码:a or 1 # 密码为随意 第二个用kali打开 3.ssh连接靶机 ssh ctf284490d0-7600-4c65-9160-5ced02f45633.node5.buuoj.cn -p 28191 由题可知密码为123456 4.找到并修改index.php文件 找到index.php文件 #内容如…...

LiveGBS流媒体平台GB/T28181功能-大屏播放上大屏支持轮巡播放分屏轮巡值守播放监控视频轮播大屏轮询播放轮播
LiveGBS支持-大屏播放上大屏支持轮巡播放分屏轮巡值守播放监控视频轮播大屏轮询播放轮播 1、轮播功能2、分屏展示3、选择轮播通道4、配置轮播间隔(秒)5、点击开始轮播6、轮播停止及全屏7、搭建GB28181视频直播平台 1、轮播功能 视频监控项目使用过程中,有时需要大屏…...
npm和pnpm安装、更换镜像源
安装pnpm 1 wins 在系统中搜索框 输入“Windos PowerShell”右击“管理员身份运行” 2 输入“set-ExecutionPolicy RemoteSigned”回车,根据提示输入A,回车 3 输入 pnpm -v 查看版本 如果没有版本好就是没有安装 pnpm 输入安装命令 npm install -g pnpm 4 再次 …...
springcloud 复习day1~[自动装配]
package com.gavin.eureka_server;public class First {private String auto"自动装配";public String getAuto() {return auto;}public void setAuto(String auto) {this.auto auto;} }package com.gavin.eureka_server;public class Second { }装配:实现ImportSe…...
模块化开发在不同编程语言中的实现方式有何异同?并以LabVIEW为例进行说明
模块化开发是一种软件设计方法,它将一个大型程序分解成独立的、可以单独开发和测试的模块或组件。这种方法提高了代码的可重用性、可维护性和可测试性。不同编程语言实现模块化开发的方式各有特色,但都遵循基本的设计原则,如封装、接口抽象和…...

外贸网站文章批量生成器
随着全球贸易的不断发展,越来越多的企业开始关注外贸市场,而拥有高质量的内容是吸引潜在客户的关键之一。然而,为外贸网站生产大量优质的文章内容可能是一项耗时且繁琐的任务。因此,外贸网站文章批量生成软件成为了解决这一难题的…...

maven一点通
1.maven简介 Maven是一个基于Java的工程构建工具,用于管理和构建项目的依赖关系。它提供了一种标准的项目结构和一组约定,使得项目的开发、构建、部署和文档化更加容易和可靠。 Maven的主要功能包括: 依赖管理:Maven可以自动下载…...

超越标签的探索:K-means与DBSCAN在数据分析中的新视角
最近在苦恼为我的数据决定分组问题,在查找资料时,恰好看到机器学习中的无监督学习的聚类分析,正好适用于我的问题,但是我之前学机器学习时。正好没有学习无监督部分,因为我认为绝大多数问题都是有标签的监督学习&#…...

linux板子vscode gdb 远程调试
板子:hi3556v200 交叉编译工具:arm-himix200-linux 主机:win10虚拟机的ubuntu16.4 gdb:gdb-8.2.tar.gz 1.在ubuntu交叉编译gdb(Remote g packet reply is too long解决) 建议修改gdb8.2/gdb目录下面的remote.c解决…...
nginx代理服务器配置
nginx代理服务器配置 需要配置环境需求 1、一台1.1.1.1服务器,一台2.2.2.2服务器 前端包路径在1.1.1.1 /etc/dist 下 后端服务在2.2.2.2 上 暴露端口为9999 2、需求 现在需要访问 1.1.1.1:80访问到2.2.2.2 上面的9999后端服务 3、配置nginx ①:在…...

基于Matlab的视频人面检测识别,Matalb实现
博主简介: 专注、专一于Matlab图像处理学习、交流,matlab图像代码代做/项目合作可以联系(QQ:3249726188) 个人主页:Matlab_ImagePro-CSDN博客 原则:代码均由本人编写完成,非中介,提供…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...