android冷启动
⑴ Android 性能优化之启动加速
当点击app的启动图标时,安卓系统会从Zygote进程中fork创建出一个新的进程分配给该应用,之后会依次创建和初始化Application类、创建MainActivity类、加载主题样式Theme中的
windowBackground等属性设置给MainActivity以及配置Activity层级上的一些属性、再inflate布局、当onCreate/onStart/onResume方法都走完了后最后才进行contentView的measure/layout/draw显示在界面上,所以直到这里,
应用的第一次启动才算完成,这时候我们看到的界面也就是所说的第一帧。所以,总结一下,应用的启动流程如下:
Application的构造器方法——>attachBaseContext()——>onCreate()——>Activity的构造方法——>onCreate()——>配置主题中背景等属性——>onStart()——>onResume()——>测量布局绘制显示在界面上。
1、冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动。
2、热启动:当启动应用时,后台已有该应用的进程(例:按back键、在已有进程的情况下,这种启动会从已有的进程中来启动应用,这个方式叫热启动
1、冷启动:冷启动因为系统会重新创建一个新的进程分配给它,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量、布局、绘制),最后显示在界面上。
2、热启动:热启动因为会从已有的进程中来启动,所以热启动就不会走Application这步了,而是直接走MainActivity(包括一系列的测量、布局、绘制),所以热启动的过程只需要创建和初始化一个MainActivity就行了,而不必创建和初始化Application
黑白屏产生原因:当我们在启动一个应用时,系统会去检查是否已经存在这样一个进程,如果不存在,系统的服务会先检查startActivity 中的intent 的信息,然后在去创建进程,最后启动Acitivy,即冷启动。
而启动出现白黑屏的问题,就是在这段时间内产生的。系统在绘制页面加载布局之前,首先会初始化窗口(Window),而在进行这一步操作时,系统会根据我们设
置的Theme 来指定它的Theme 主题颜色,我们在Style 中的设置就决定了显示的是白屏还是黑屏。
1.Application 优化(懒加载,延时加载)
2.UI效果,背景图
3.fragment的懒加载
4.延时加载
⑵ 安卓大屏导航冷启动和热启动的区别
冷启动:
在启动应用时,系统中没有该应用的进程,这时系统会创建一个新的进程分配给该应用;
热启动:
在启动应用时,系统中已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程还是保留在后台);
二、冷启动、热启动的区别
冷启动:系统没有该应用的进程,需要创建一个新的进程分配给应用,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量、布局、绘制),最后显示在界面上。 热启动: 从已有的进程中来启动,不会创建和初始化Application类,直接创建和初始化MainActivity类(包括一系列的测量、布局、绘制),最后显示在界面上。
三、冷启动时间的计算
API19 之后,系统会出打印日志输出启动的时间; 冷启动时间 = 应用启动(创建进程) —> 完成视图的第一次绘制(Activity内容对用户可见);
四、冷启动流程
Zygote进程中fork创建出一个新的进程; 创建和初始化Application类、创建MainActivity; inflate布局、当onCreate/onStart/onResume方法都走完; contentView的measure/layout/draw显示在界面上;
总结:
Application构造方法 –> attachBaseContext() –> onCreate() –> Activity构造方法 –> onCreate() –> 配置主题中背景等属性 –> onStart() –> onResume() –> 测量布局绘制显示在界面上。
五、冷启动的优化
减少在Application和第一个Activity的onCreate()方法的工作量; 不要让Application参与业务的操作; 不要在Application进行耗时操作; 不要以静态变量的方式在Application中保存数据; 减少布局的复杂性和深度;
1. 冷启动的定义
冷启动:启动应用前,系统中没有该应用的任何进程信息Application等,启动5s+。
1.1 冷启动时间的计算
这个时间值是从应用启动(创建进程)开始计算,到完成视图的第一次绘制(即Activity内容对用户可见)为止。
2. 热启动的定义
热启动:启动应用时,后台已有该应用的进程,内存中有应用相关Activity(home键退到桌面),启动1.5s+。
3. 温启动的定义
有一些文章有温启动这个启动类型。
温启动:启动应用时,后台已有该应用的进程,内存中没有应用相关Activity(back键退出应用,未清除进程),启动2s+。
冷热启动过程中,会执行的步骤不一样。
冷启动:系统会重新创建一个新的进程分配给它,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量、布局、绘制),最后显示在界面上。
热启动:一个应用从新进程的创建到进程的销毁,Application只会初始化一次,所以不必创建和初始化Application,直接走MainActivity(包括一系列的测量、布局、绘制)。
二.冷启动流程
当点击app的启动图标时,安卓系统会从Zygote进程中fork创建出一个新的进程分配给该应用,之后会依次创建和初始化Application类、创建MainActivity类、加载主题样式Theme中的windowBackground等属性设置给MainActivity以及配置Activity层级上的一些属性、再inflate布局、当onCreate/onStart/onResume方法都走完了后最后才进行contentView的measure/layout/draw显示在界面上,所以直到这里,应用的第一次启动才算完成,这时候我们看到的界面也就是所说的第一帧。详细的参考:App(Activity)启动流程
总结应用的启动流程如下:
Application的构造器方 -> attachBaseContext() -> onCreate() -> Activity的构造方法 -> onCreate() -> 配置主题中背景等属性 -> onStart() -> onResume() -> 测量布局绘制显示在界面上。
三.如何对冷启动的时间进行优化
冷启动时,加载Application过程中,可能会消耗很多时间。如果不采取任何措施就会产生长时间的白屏或黑屏效果,让用户以为这个应用很卡。消除启动时的白屏/黑屏,请参考:Android冷启动实现APP秒开
1、什么是Android的冷启动时间?
冷启动时间是指用户从手机桌面点击APP的那一刻起到启动页面的Activity调用onCreate()方法之间的这个时间段。
2、在冷启动的时间段内发生了什么?
首先我们要知道当打开一个Activity的时候发生了什么,在一个Activity打开时,如果该Activity所属的Application还没有启动,那么系统会为这个Activity创建一个进程(每创建一个进程都会调用一次Application,所以Application的onCreate()方法可能会被调用多次),在进程的创建和初始化中,势必会消耗一些时间,在这个时间里,WindowManager会先加载APP里的主题样式里的窗口背景(windowBackground)作为预览元素,然后才去真正的加载布局,如果这个时间过长,而默认的背景又是黑色或者白色,这样会给用户造成一种错觉,这个APP很卡,很不流畅,自然也影响了用户体验。
⑶ Android 中应用程序Activity的冷启动流程
Activity的启动主要涉及四个进程
SystemServer进程:主要负责管理整个Framework
App进程:app用户点击桌面icon时,通过Launcher进程请求SystemServer进程,再通知Zygote孵化的。
Zygote进程:所有的应用进程都是有Zygote孵化出来的,而Zygote进程由init进程孵化出来,init进程的子进程。
Launcher 进程 :Zygote进程孵化的第一个应用进程。
Activity的启动主要涉及到七个阶段
第一阶段: Launcher通知AMS要启动新的Activity(在Launcher所在的进程执行)
第二阶段:AMS先校验一下Activity的正确性,如果正确的话,会暂存一下Activity的信息。然后,AMS会通知Launcher程序pause Activity(在AMS所在进程执行)
第三阶段: pause Launcher的Activity,并通知AMS已经paused(在Launcher所在进程执行)
第四阶段:检查activity所在进程是否存在,如果存在,就直接通知这个进程,在该进程中启动Activity;不存在的话,会调用Process.start创建一个新进程(执行在AMS进程,内部通过socket和Zygote通信,fork一个新进程)
第五阶段: 创建ActivityThread实例,执行一些初始化操作,之后进入Loop循环。(执行在新创建的app进程)
第六阶段:处理新的应用进程发出的创建进程完成的通信请求,并通知新应用程序绑定Application。如果Application不存在,会调用LoadedApk.makeApplication创建一个新的Application对象。并且通知进程启动目标Activity组件(执行在AMS进程)
第七阶段: 加载MainActivity类,调用onCreate声明周期方法(执行在新启动的app进程)
最后我们来简单总结一下Activity的启动流程。
1、startActivity
2、Instrumentation请求AMS启动Activity(Binder)
3、AMS请求Zygote开启进程
4、Zygote创建应用进程
5、应用进程启动ActivityThread(主线程)
6、ActivityThread绑定Application
8、ActivityThread启动Activity
9、调用Activity的onCreate方法
⑷ Android启动优化概述
Android启动应用, 按 官方说法 分为冷启动, 温启动和热启动.
具体的定义可以看官方文档, 简单地说
一般我们只需要关注冷启动即可.
要想启动快, 硬件性能必然有影响, 在硬件一定的前提下, 我们要尽量 降低启动应用时CPU的负载 , 让CPU有更多的算力投入到启动流程中:
在做好一些基本原则后, 接着看具体的流程优化点
在应用进程创建后, 首先必然是加载类, 此时一些静态变量就会初始化了, 因此我们应该
类加载完毕后就是创建 Application 实例了, 因此我们应该
之后会先创建 ContentProvider 和执行 ContentProvider.onCreate() , 因此我们应该
跟接着就会执行 Application.onCreate() 等方法, 因此我们应该
接着就进入 Activity 环节.
同样第一步会是创建实例, 因此我们应该
在 Activity 进程生命周期后, 第一步就是渲染(inflate)布局, 我们应该
在应用启动的瞬间, 系统服务会先展示一个空白窗口, 等待应用第一帧绘制完毕后, 再从该窗口切换到应用, 如果启动耗时较长, 就会明显看到白屏, 对于这一点, 常见的操作有
可以使用IdleHandler, 在主线程空闲时再执行某些不重要的操作
实际上异步初始化只是不阻塞主线程, 但是子线程一样会占用CPU资源, 让主线程的执行时间变少, 所以不应该盲目地将所有工作放到子线程.
优化做到最后, 就是在系统流程上做文章了
原理是将启动时加载的类放到主dex,提升了这些类的内聚,让更多的类满足pre-verify的条件,在安装时就做了校验和优化,以减少首次加载的耗时,从而优化冷启动耗时。
Redex 初探与 Interdex:Andorid 冷启动优化
应用启动过程中会从apk压缩包中读取文件, 该优化的原理是利用Linux中的Pagecache机制, 让启动过程会用到的文件尽可能进入缓存中, 减少磁盘IO次数
支付宝 App 构建优化解析:通过安装包重排布优化 Android 端启动性能
在Dalvik VM(Android5.0以前)加载类的时候会有一个类校验过程, 它需要校验方法的每一个指令, 是一个比较耗时的过程, 可以通过Hook去掉类加载过程中的类验证过程. 不过对于ART(Android5.0之后)来说, 这个过程在安装时已经做了, 所以用处不大.
不进入冷启动, 就不用优化了~
这个Android Studio自带的工具, 可以看到启动过程中详细的方法执行流程, 但是采集数据本身会影响方法执行, 所以不能准确判断每个方法的耗时, 但是仍可以判断哪个方法相对来说耗时.
这个工具的好处是可以自定义事件, 可以指定需要采集的数据集, 可以看到线程间的状态等.
启动优化的一个关键点在于定义启动结束的点, 以及如何测量启动时间.
在Android4.4以上, 系统进程会提供一个类似 ActivityManager: Displayed ***: +3s534ms 的日志, 表示从启动进程到首次绘制完毕所用的时间.
应用可以在任何时候调用该方法, 触发系统打印类似 system_process I/ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms 的日志
应用可以通过 ViewTreeObserver 来监听绘制前回调来判断第一帧的绘制时机, 或者直接在控件树的末尾加一个简单的View, 它 onDraw 调用时即表示页面(差不多)绘制完毕.
应用启动过程可以参考 Android Vitals Series' Articles 系列文章
⑸ Android 11 提高 App 冷启动速度 5% 以上
近一年多以来一直在做性能优化( OOM、Native、ANR 等等),在后面我也会写一些性能相关的文章,将自己学习和实践所得分享出来。以今天这篇文章作为开端。
在 Android 11 上增加了一个新的功能 IORap,IORap 将会减少 App 冷启动耗时,经过在各种设备上测试,App 的启动速度(冷启动)平均提高了 5% 以上,部分设备提高了 20% 以上,开发者不需要做任何任何事情,即可享受带来的启动优化收益。
IORap 会提前预测需要那些 I/O 并将他们提前,通过这种方式减少 App 启动耗时。大量的 App 启动时间很长,是因为 blocking I/O 导致 IO 请求队列未到达饱和,在预取数据之后同时压缩 I/O ,App 可以很快的从 kernel pagecache 中访问预取数据,从而减少 App 启动耗时。
我们测试了在 Google Play Store 上一些热门的应用,80% 的 App 在启动期间,因为 blocking I/O 耗费了 10% 以上的时间,80% 的 App 耗费了 20% 以上的时间。我们在 Google Play Store 上测试了大部分应用都可以从 IORap 中获得收益。
IORap 作为一个独立的 service,它通过 IPC 与 package manager,activity manager, perfetto service 等等交互,以下是 IORap 的架构图。
IORap 基于一定的策略分析预取 I/O ,通过 perfetto 进行跟踪记录,会在 kernel pagecache 中添加和删除的页面。经过测试,启动期间通过 perfetto 进行跟踪记录造成的开销可以忽略不计。
基于上面的 perfetto trace,IORap 会在设备空闲时,生成预取列表,预取列表包含启动期间需要读取的文件信息(名称,偏移,长度), IORap 会根据 perfetto trace 分析 mm_pagemap 事件,并将结果 (inode、偏移量、长度) 转换为 (名称、偏移量、长度),然后将数据存储在预取列表中,预取列表是一个 protobuf 文件。
经过上一步,生成预取列表之后,后续运行 App 时 IORap 可以为 App 预取对应的数据,在上一步执行完之后,不在需要 perfetto trace, 开发者不需要做任何事情,系统会在用户点击图标时或者通过 Intent 请求它,执行预取操作,享受带来的启动优化。
预取列表不会永久存在,会因为一些事件导致预取列表过时,而被删除,当 App 更新时,由于更新过程中可能会发生变化,和之前的预取数据会有一些差异,所以不建议在这个阶段预取数据,另外 dexopt 会在 App 安装后进行优化,优化后的 App,数据不会发生改变,这会使预取列表过时,过时的预取列表将被删除,这时会开始新一轮的 perfetto trace。
通过对比几个实验的结果,我们可以确定 IORap 对于低端机和高端机都会有收益,平均而言, IORAP 可以提高 26% 的启动速度,对于启动期间有大量 I/O 的 App 会有很大的帮助,例如,Spotify 低端设备和高端设备有两位数字的优化效果。
在实验过程中,发现了一个现象 IORap 性能会受到预取数据的影响,跟踪持续时间对于 IORap 来说非常重要,跟踪持续时间越短,预取的数据就越少,获得的性能也越低。另一方面,长时间的预取会导致需要预取的数据过多,这可能会导致启动速度变慢,我们可以根据 ReportFullyDrawn 事件的时间戳来估计跟踪持续时间。在正确的调用 reportFullyDrawn 回调可以提高 IORap 的性能。
我们对 IORap 所表现出来的性能非常的兴奋,在未来将会朝着以下两方向进行优化。
可以在 App 启动完成之后,调用 reportFullyDrawn 来帮助 IORap 进行更好的优化,IORap 主要有助于减少 I/O 阻塞时间,因此可以考虑对 App 启动进行分析,发现和解决其他可能存在的性能问题。