当前位置: 首页 > 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…...

以 Java NIO 的角度理解 Netty

文章目录 前言Java NIO 工作原理Selector 的创建ServerSocketChannel 的创建ServerSocketChannel 注册 Selector对事件的处理总结 前言 上篇文章《Netty 入门指南》主要涵盖了 Netty 的入门知识&#xff0c;包括 Netty 的发展历程、核心功能与组件&#xff0c;并且通过实例演示…...

Maven自定义脚手架(多module模块)+自定义参数

脚手架 视频教程&#xff1a; Maven保姆级教程 脚手架是一个项目模板&#xff0c;包含常用的工程结构、代码。 1 自定义脚手架 脚手架创建的步骤如下&#xff0c;先创建一个工程&#xff0c;把常用的代码写好&#xff0c;进入工程根目录&#xff0c;进行如下操作&#xff1a; …...

爬虫逆向实战(七)--猿人学第十六题

一、数据接口分析 主页地址&#xff1a;猿人学第十六题 1、抓包 通过抓包可以发现数据接口是api/match/16 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以看出m是加密参数 请求头是否加密&#xff1f; 无响应是否加密&#xff1f; 无cook…...

Qt 杂项(Qwt、样式等)

Qt隐藏窗口边框 this->setWindowFlags(Qt::FramelessWindowHint);Qt模态框 this->setWindowModality(Qt::ApplicationModal);QLable隐藏border 代码中设置 lable->setStyleSheet("border:0px");或者UI中直接设置样式&#xff1a;“border:0px” Qwt开源…...

Python程序设计——列表

一、引言 关键点&#xff1a;一个列表可以存储任意大小的数据集合。 程序一般都需要存储大量的数值。假设&#xff0c;举个例子&#xff0c;需要读取100个数字&#xff0c;计算出它们的平均值&#xff0c;然后找出多少个数字是高于这个平均值的。程序首先读取100个数字并计算它…...

NPDP含金量高吗?难考吗?

一&#xff0c;什么是NPDP认证&#xff1f; NPDP认证中文名为产品经理国际资格认证&#xff0c;New Product Development Professional (NPDP) &#xff0c;是由美国 产品开发与管理协会 (PDMA) 所发起&#xff0c; 是国际公认的唯一的新产品开发专业认证&#xff0c;集理论、方…...

windows pip安装出现 error: Microsoft Visual C++ 14.0 is required

可参考&#xff1a;如何解决 Microsoft Visual C 14.0 or greater is required. Get it with “Microsoft C Build Tools“_不吃香菜的小趴菜的博客-CSDN博客 一、安装Visual Studio2022 1、下载&#xff1a;下载 Visual Studio Tools - 免费安装 Windows、Mac、Linux 我这使…...

威胁分析风险评估(TARA)影响和攻击可行性评估参考

在威胁分析风险评估&#xff08;TARA)过程中&#xff0c;风险等级由对资产安全属性侵害造成后果的影响等级和威胁的可能性两方面综合评估。 备注&#xff1a;以上内容的评估皆是建立在由信息安全问题引起并导致的前提下。 影响等级评估 影响等级说明&#xff0c;影响从安全&a…...

【教程】H5匿名信源码下载一封来信系统安装流程搭建教程

1、下载源码 匿名信2.0&#xff1a;匿名信h5源码 - 万策云盘 提取码&#xff1a;hOC4 2、查看搭建和使用教程 1,准备授权好的域名和服务器还有源码 2&#xff0c;创建网站和数据库&#xff0c;版本选择7.1【不可以选7.2】 3&#xff0c;上传源码并解压&#xff0c;导入数据…...

PyTorch训练简单的生成对抗网络GAN

文章目录 原理代码结果参考 原理 同时训练两个网络&#xff1a;辨别器Discriminator 和 生成器Generator Generator是 造假者&#xff0c;用来生成假数据。 Discriminator 是警察&#xff0c;尽可能的分辨出来哪些是造假的&#xff0c;哪些是真实的数据。 目的&#xff1a;使…...