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

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...