冷启动笔记

107 阅读6分钟

1 冷启动定义 :

应用从头开始启动,系统进程在冷启动后才创建应用进程。

2 冷启动系统任务:

1 加载并启动应用

2 启动后立即显示SplashActivity的window背景

3 创建应用进程

(OnCreate()至少执行两次,分别为Appplication和Activity,如果有多个进程则会执行多次Appplication中的onCreate)

  1. 创建应用对象,应该是初始化Application,执行Appplication的OnCreate() 方法
  2. 启动主线程
  3. 创建SplashActivity,开始准备要启动Activity 也就是走Activity的OnCreate()方法
  4. (加载View)Inflating SplashActivity的xml,变成View
  5. 把上面的View 布局到 SplashActivity
  6. 执行绘制流程,当绘制完成,系统就会替换当前的window,替换成要启动的SplashActivity,也就是onResume()和onAttachedToWindow()方法执行完成,也就是当View的onDraw()方法执行完,渲染完毕之后用户就会看到 SplashActivity界面的UI。

2 冷启动流程:

  1. 启动进程。
  2. 初始化对象。
  3. 创建并初始化 Activity。
  4. 填充布局。
  5. 绘制完第一帧。

3 从代码/执行流程优化冷启动

  1. 异步初始化
  2. 延迟初始化
  3. 懒初始化,用到时再初始化
  4. 线程问题,线程优先级

线程是一个比较珍贵的东西,一个进程中,如果不设置线程的优先级,每个线程都会相同几率来获取CPU的时间片。就会导致主线程执行的时间变小,所以可以设置线程优先级,来增大分配主线程的时间片的几率

  1. 延迟初始化线程池 , 在Application中 或者 SplashActivity中,用一个线程 要 比 用一个线程池要强的多,可以延迟初始化线程池,
  2. 网络请求,尽量减少网络请求
  3. IO/数据库操作 IO 放到子线程中
  4. 避免GC,因为GC会出发Stop The World
  5. 减少两处onCreate()中的初始化操作,将部分初始化移动到IntentService中进行(IntentService在 API30 弃用)
  6. 如果有多个进程的话,Application会初始化多次,也就是每一个进程都会走一遍Application的onCreate(),虽然其他进程初始化的Application不会影响主进程的速度,但是会影响整个手机的内存大小。所以当我们app中有多进程的时候,在onCreate中可以判断是不是主进程,之后再初始化东西

4 Activity绘制优化

  1. 避免xml过大,因为读取xml就已经很耗时了
  2. 布局层级尽量少 因为读取View的时候,是个递归操作
  3. View的onLayout,onMeasure,onDraw() 中 避免耗时操作
  4. 减少非必要的背景

5 启动页Activity的优化

  1. 布局优化

我们的启动页Activity包含有启动图控件、闪屏广告图控件、闪屏广告视频控件、首次安装介绍图控件。对于布局优化而言,除了启动图控件外,其他都不是App启动时都要初始化的控件,这时我们可以使用ViewStub。针对指定的业务场景,初始化指定的控件。

  1. 避免I/O操作

我们知道I/O操作不是实时的,例如数据库的读写、SharedPreferences#apply()。我们要注意这些操作有没阻塞主线程地执行,同时我们可以利用StrictMode严格模式,利用它可以检测我们在启动的时候有没正确进行磁盘读写操作。

  1. 注意图片bitmap的加载速度和编码格式

我们可以知道,启动页大部分的情况下都是图片的显示,那么我们在图片这方面怎么抠细节呢,那就是对各种第三方图片加载库的选用了Glide、Picasso、Fresco等,还有是PREFER_ARGB_8888、PREFER_RGB_565的选取问题,大家可以针对属于自己项目情况进行选取。

  1. 对矢量图VectorDrawable对象的使用

矢量图的核心是省时间、省空间。而对于某些用户,它的启动图可能不是一张图片,它十分简约,就一个logo,这个时候我们可以考虑一下矢量图的用法。

  1. 注意Activity中的启动生命周期的回调

我们在Application#onCreate()优化,将某些不是很必要的网络请求,搬到了欢迎页中,但是我们也不能直接将这个网络请求操作直接拷贝到启动页的onCreate()中,我们可以巧妙地利用Activity生命周期中的Activity#onWindowFocusChanged(boolean hasFocus) ,这个是所有控件初始化完的真正回调,我们可以将网络操作放在这里,当然我们还可以使用Service。

==================================================================================

1 Systrace使用

工具路径:/home/mi/Android/Sdk/platform-tools

$ python ./systrace.py -o test.html power -a com.android.camera

open chrome, enter "chrome://tracing", and click the "load" button to load your trace html file.

代码添加trace:

Trace.``beginSection``("begin");

Trace.``endSection``();

命令和命令选项

命令和选项描述
-o file将 trace 的网页报告写到指定的文件中。若未指定该选项,systrace 会保存报告至与 systrace.py 相同的目录下,同时命名 trace.html
-t N 或 - -time=NTrace 设备活动的 N 秒时间。若未指定该选项,命令行中,通过敲 Enter 回车键来终止 trace 进程
-b N 或 - -buf-size=N使用 N 千字节的 trace 缓冲区大小。这个选项可以限制在 trace 期间总共收集数据的大小
-k functions 或 - -ktrace=functionsTrace 指定内核方法的活动,指定于逗号分隔的列表
-a app-name或 - -app=app-name追踪应用包名,用逗号分隔
--from-file=file-path从一份文件里创建交互式的网页报告,如从包括原始 trace 数据的 TXT 文件,而不是运行着动态的 trace
-e device-serial或 - -serial=device-serial根据设备的 serial number,在指定连接的设备上执行 trace
categories指定跟踪的类型,例如gfx用于呈现图形的系统进程。

2 Systrace报告

(1) 快捷键

  1. 导航
导航操作作用
w放大,[+shift]速度更快
s缩小,[+shift]速度更快
a左移,[+shift]速度更快
d右移,[+shift]速度更快
  1. 快捷操作
常用操作作用
f放大当前选定区域(放大选定的一块)
m标记当前选定区域(可以显示时间长度)
v高亮VSync(所在的一帧)
g切换是否显示60hz的网格线(同上)
0恢复trace到初始态,这里是数字0而非字母o(缩小到初始)
h切换是否显示详情
/搜索关键字
enter显示搜索结果,可通过← →定位搜索结果
`显示/隐藏脚本控制台
?显示帮助功能

每个线程有颜色表示各自不同的状态:

灰色:正在休眠。

蓝色:可运行(它可以运行,但是调度程序尚未选择让它运行)。

绿色:正在运行(调度程序认为它正在运行)。

红色:不可中断休眠(通常在内核中处于休眠锁定状态)。可以指示 I/O 负载,在调试性能问题时非常有用。

橙色:由于 I/O 负载而不可中断休眠。