当前位置: 首页 > news >正文

Android 应用冷启动优化

冷启动相关概念

应用启动概念

  • 冷启动:首次打开app或者app彻底销毁后再次打开app(开关机后),这也是我们进行启动速度优化的主要方向。
  • 热启动:应用运行中按home键再打开应用。
  • 温启动:介于两者之间,比如:说用户关闭应用又重新启动应用,这是应用进程还没被销毁。或者系统主动释放掉后台应用,然后用户就将它启动,这时虽然要再重新执行onCreate,但是saveInstanceState实例已经保存,可以提高启动速度。

谷歌官方应用启动时间说明

冷启动时间

冷启动优化就是要缩短冷启动的时间,冷启动时间获取方法,先kill掉进程,或者重新安装一个应用,串口输入下面的命令:

am start -W com.jane.demo/.MainActivity

发送命令后有下面的数据,TotalTime是冷启动的时间。

Status: ok
LaunchState: COLD
Activity: com.jane.demo/.MainActivity
TotalTime: 788
WaitTime: 792

冷启动优化方法

优化前注意应用版本(debug还是release),之前新建一个空项目(只显示一个hello world),想测试想一个空项目启动大概需要多长时间。结果用了接近800ms,震惊不已,后面发现是debug版本的原因,改为release后400ms,降低了一半。

布局加载优化

1、减少布局复杂度

可以使用merge等减少界面层级,这个是比较常用的方法。

2、异步加载

也可以使用异步加载布局的方式AsyncLayoutInflaterAsyncLayoutInflater是谷歌提供的一个异步加载UI方案,其可以异步加载控件并回调给UI,以此减少主线程消耗。对源码和实现原理感兴趣的可以看到后面的参考文章,这里简单看下使用方式:

先在appgradle下加入依赖包。

 implementation 'androidx.asynclayoutinflater:asynclayoutinflater:1.0.0'

如下为测试代码:

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {//测试1:使用原始方式加载//setContentView(R.layout.activity_main);//测试2:使用AsyncLayoutInflater异步加载new AsyncLayoutInflater(this).inflate(R.layout.activity_main,null, new AsyncLayoutInflater.OnInflateFinishedListener(){@Overridepublic void onInflateFinished(View view, int resId, ViewGroup parent) {setContentView(view);         }}); }
}
  • 第一次测试,onCreate中直接调用setContentView(),然后看冷启动时间:TotalTime: 829
  • 第二次测试,使用AsyncLayoutInflater异步加载,冷启动时间:TotalTime: 712

启动耗时操作后移

Android 12 SplashScreen API快速入门在郭神的这个文章中,通过验证得出结论:onCreate()onResume()等生命周期方法都是在App开始绘制第一帧之前执行的,因此在这些生命周期函数中,耗时的操作应该后移或者放到子线程处理。

1、使用View.post()方法后移耗时操作

郭神的文章有分析,post()回调则是在App绘制第一帧之后执行的。因此可以在View.post()方法后,再执行耗时操作。这个方法要比使用Handlerdelay要好,因为delay的时间是不确定的。

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());View rootView = mActivityMainBinding.getRoot();setContentView(rootView);//测试1:耗时300ms操作/* try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}*/       rootView.post(new Runnable() {@Overridepublic void run() {//测试2:耗时300ms操作try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}}});            }
}
  • 第一次测试,把300ms耗时操作直接放在onCreate中,然后看冷启动时间:TotalTime: 1124
  • 第二次测试,把300ms耗时操作放在IdleHandler的回调中,冷启动时间:TotalTime: 853

2、使用IdleHandler,后移耗时操作

IdleHandler会在MessageQueue中没有Message要处理或者要处理的Message都是延时任务的时候得到执行,说明此时线程是空闲状态。如果是在主线程,则表明当前UI没有绘制动作,所以可以根据监听IdleHandler是否执行来判断UI是否绘制完成,从而避免在UI绘制的时候进行耗时操作,影响UI绘制效率。

queueIdle()方法回调,说明UI第一帧绘制完成,可以理解为UI首次可见,这个比onResume精确的多,因为onResume回调的时候界面还没有开始绘制,此时界面是不可见的,测试代码如下;

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());View rootView = mActivityMainBinding.getRoot();setContentView(rootView);//测试1:耗时300ms操作/* try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}*/Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {@Overridepublic boolean queueIdle() {//此处添加处理任务//测试2:耗时300ms操作try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}// 返回false表示MessageQueue在执行完这段代码后将该IdleHandler删除,反之不删除,下一次继续执行return false;}});}
}
  • 第一次测试,把300ms耗时操作直接放在onCreate中,然后看冷启动时间:TotalTime: 1124
  • 第二次测试,把300ms耗时操作放在IdleHandler的回调中,冷启动时间:TotalTime: 878

3、使用子线程处理耗时操作

在测试用,将模拟的耗时操作放到了子线程中执行,后面又给子线程加上了一个最低的优先级。

在Android中,线程优先级范围从1到10,其中1是最低优先级,10是最高优先级。默认情况下,所有线程都具有相同的优先级5,也就是new一个线程出来优先级就是5。

通过设置线程的优先级,我们可以改变线程在调度器中的竞争情况,从而影响其执行顺序。推荐在Application的某些初始化方法使用子线程加载。

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());View rootView = mActivityMainBinding.getRoot();setContentView(rootView);//测试1:耗时300ms操作/* try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}*///测试2:开一个子线程操作Thread thread = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}}}//测试3:给子线程加一个低的优先级thread.setPriority(Thread.MIN_PRIORITY);thread.start();}
}
  • 第一次测试,把300ms耗时操作直接放在onCreate()中,然后看冷启动时间:TotalTime: 1124
  • 第二次测试,把300ms耗时操作放在子线程中,冷启动时间:TotalTime: 776
  • 第三次测试,给子线程加一个低的优先级,冷启动时间:TotalTime: 730

实际测试中,第二次和第三次时间其实是差不多的,都有大一点有小一点的,这个在我的测试代码中优化不明显。但是还是建议加上,不然也会争抢主线程资源,影响优化启动时间。

码字不易有帮助到大家请点赞、收藏,谢谢。

参考文章:

【Android笔记】异步加载View,AsyncLayoutInflater原理
IdleHandler原理及使用

相关文章:

Android 应用冷启动优化

冷启动相关概念 应用启动概念 冷启动:首次打开app或者app彻底销毁后再次打开app(开关机后),这也是我们进行启动速度优化的主要方向。热启动:应用运行中按home键再打开应用。温启动:介于两者之间&#xff…...

538页21万字数字政府智慧政务大数据云平台项目建设方案WORD

导读:原文《538页21万字数字政府智慧政务大数据云平台项目建设方案WORD》(获取来源见文尾),本文精选其中精华及架构部分,逻辑清晰、内容完整,为快速形成售前方案提供参考。 根据业务的不同属性&#xff0c…...

进程间通信——信号

信号的概念 信号是 Linux进程间通信的最古老的方式之一,是事件发生时对进程的通知机制,有时也称之为软件中断,它是在软件层次上对中断机制的一种模拟,是一种异步通信的方式。信号可以导致一个正在运行的进程被另一个正在运行的异…...

PAT 1039 Course List for Student

个人学习记录,代码难免不尽人意。 Zhejiang University has 40000 students and provides 2500 courses. Now given the student name lists of all the courses, you are supposed to output the registered course list for each student who comes for a query. …...

【Sklearn】基于决策树算法的数据分类预测(Excel可直接替换数据)

【Sklearn】基于决策树算法的数据分类预测(Excel可直接替换数据) 1.模型原理1.1 模型原理1.2 数学模型2.模型参数3.文件结构4.Excel数据5.下载地址6.完整代码7.运行结果1.模型原理 决策树是一种基于树状结构的分类和回归模型,它通过一系列的决策规则来将数据划分为不同的类…...

并发编程4:Java 中的并发基础构建模块

目录 1、同步容器类 1.1 - 同步容器类的问题 1.2 - 迭代和容器加锁 2、并发容器类 2.1 - ConcurrentHashMap 类 2.2 - CopyOnWriteArrayList 类 3、阻塞队列和生产者-消费者模式 3.1 - 串行线程封闭 4、阻塞方法与中断方法 5、同步工具类 5.1 - 闭锁 -> CountDow…...

Vue-10.集成(.editorconfig、.eslintrc.js、.prettierrc)

介绍 同时使用 .editorconfig、.prettierrc 和 .eslintrc.js 是很常见的做法,因为它们可以在不同层面上帮助确保代码的格式一致性和质量。这种组合可以在开发过程中提供全面的代码维护和质量保证。然而,这也可能增加一些复杂性,需要谨慎配置…...

PHP-FPM进程排查

1、查看php-fpm的进程个数 ps -ef |grep "php-fpm"|grep "pool"|wc -l2、查看每个php-fpm占用的内存大小 ps -ylC php-fpm --sort:rss3.查看PHP-FPM在你的机器上的平均内存占用 ps --no-headers -o "rss,cmd" -C php-fpm | awk { sum$1 } END…...

PHP-MD5注入

0x00 前言 有些零散的知识未曾关注过,偶然捡起反而更加欢喜。 0x01 md5 注入绕过 md5函数有两个参数,第一个参数是要进行md5的值,第二个值默认为false,如果为true则返回16位原始二进制格式的字符串。意思就是会将md5后的结果当…...

对redis、redisson、springcache总结

<一> redis-缓存中间件 什么是redis redis是c语言开发的&#xff0c;一个高性能key-value键值对内存数据库&#xff0c;可以用来做数据库、缓存、消息中间件的一种非关系型数据库。 redis数据存储在哪里 内存和磁盘中&#xff0c;但是redis的读写都在内存中&#xff0c;…...

Java基础知识实际应用(学生信息管理系统、猜拳小游戏、打印日历)

一、Java学生信息管理系统 这个系统包含了添加、修改、删除、查询和显示所有学生信息等功能。您可以在此基础上进行修改和完善&#xff0c;以适应您的需求。 import java.util.Scanner;public class StudentManagementSystem {private static Scanner scanner new Scanner(S…...

Git:在本地电脑上如何使用git?

git 版本&#xff1a; 2.40.1.windows.1 文章目录 一. 使用git之前你必须要理解的几个概念1.1 理解工作区、版本库、暂存区的概念1.2 提交Git版本库的步骤【分两步执行】 二. Git本地库实战2.1 初始化版本库2.2 新建 & 提交 & 状态2.3 查看日志2.4 回退 & 穿梭 &am…...

卷和分区的关系

1、分区 存储空间管理和仓库管理类似&#xff0c;只不过仓库管理的是货物&#xff0c;存储空间管理的是文件。当仓库规模小时&#xff0c;可以不划分货物的存放区域&#xff0c;但当仓库规模很大&#xff0c;就必须根据货物的类型和存储需要&#xff0c;把仓库分为多个区域。例…...

Linux下在qtcreator中创建qt程序

目录 1、新建项目 2、单工程项目创建 3、多工程项目创建 4、添加子工程&#xff08;基于多工程目录结构&#xff09; 5、 .pro文件 1、新建项目 切换到“编辑”界面&#xff0c;点击菜单栏中的“文件”-“新建文件或项目” 2、单工程项目创建 只有一个工程的项目&#…...

快递再多也不怕!你的顺丰快递用上5G“神器”

互联网时代&#xff0c;剁手党疯狂“买买买”之后&#xff0c;快递件量再创新高。《2023年6月中国快递发展指数报告》显示&#xff0c;2023二季度单月快递业务量稳定在百亿件以上。其中&#xff0c;由于“618”电商促销活动与父亲节叠加&#xff0c;6月16日至20日单日揽收量均超…...

微信小程序:模板使用

目录 模板的优点&#xff1a; 一、静态模板创建 二、静态模板使用 1.*.wxml引入模板 2.模板使用 3.*.wxss引入模板的样式 三、动态模板创建 四、动态模板使用 1.*.wxml引入模板 2.模板使用 3.*.js定义动态数据 五、结果展示 总结 模板的优点&#xff1a; 有利于保持网…...

AUTOSAR NvM Block的三种类型

Native NVRAM block Native block是最基础的NvM Block&#xff0c;可以用来存储一个数据&#xff0c;可以配置长度、CRC等。 Redundant NVRAM block Redundant block就是在Native block的基础上再加一个冗余块&#xff0c;当Native block失效&#xff08;读取失败或CRC校验失…...

Vue+ElementUI实现选择指定行导出Excel

这里记录一下&#xff0c;今天写项目时 的一个需求&#xff0c;就是通过复选框选中指定行然后导出表格中选中行的Excel表格 然后这里介绍一个工具箱(模板)&#xff1a;vue-element-admin 将它拉取后&#xff0c;运行就可以看到如下界面&#xff1a; 这里面的很多功能都已经实现…...

SNMP简单介绍

SNMP SNMP是广泛应用于TCP/IP网络的网络管理标准协议&#xff0c;该协议能够支持网络管理系统&#xff0c;用以监测连接到网络上的设备是否有任何引起管理上关注的情况。SNMP采用轮询机制&#xff0c;提供最基本的功能集&#xff0c;适合小型、快速、低价格的环境使用&#xf…...

使用python对图像加噪声

加上雨点噪声 import cv2 import numpy as npdef get_noise(img, value10):#生成噪声图像>>> 输入&#xff1a; img图像value 大小控制雨滴的多少 >>> 返回图像大小的模糊噪声图像noise np.random.uniform(0, 256, img.shape[0:2])# 控制噪声水平&#xff…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...