1 冷启动定义 :
应用从头开始启动,系统进程在冷启动后才创建应用进程。
2 冷启动系统任务:
1 加载并启动应用
2 启动后立即显示SplashActivity的window背景
3 创建应用进程
(OnCreate()至少执行两次,分别为Appplication和Activity,如果有多个进程则会执行多次Appplication中的onCreate)
- 创建应用对象,应该是初始化Application,执行Appplication的OnCreate() 方法
- 启动主线程
- 创建SplashActivity,开始准备要启动Activity 也就是走Activity的OnCreate()方法
- (加载View)Inflating SplashActivity的xml,变成View
- 把上面的View 布局到 SplashActivity
- 执行绘制流程,当绘制完成,系统就会替换当前的window,替换成要启动的SplashActivity,也就是onResume()和onAttachedToWindow()方法执行完成,也就是当View的onDraw()方法执行完,渲染完毕之后用户就会看到 SplashActivity界面的UI。
2 冷启动流程:
- 启动进程。
- 初始化对象。
- 创建并初始化 Activity。
- 填充布局。
- 绘制完第一帧。
3 从代码/执行流程优化冷启动
- 异步初始化
- 延迟初始化
- 懒初始化,用到时再初始化
- 线程问题,线程优先级
线程是一个比较珍贵的东西,一个进程中,如果不设置线程的优先级,每个线程都会相同几率来获取CPU的时间片。就会导致主线程执行的时间变小,所以可以设置线程优先级,来增大分配主线程的时间片的几率
- 延迟初始化线程池 , 在Application中 或者 SplashActivity中,用一个线程 要 比 用一个线程池要强的多,可以延迟初始化线程池,
- 网络请求,尽量减少网络请求
- IO/数据库操作 IO 放到子线程中
- 避免GC,因为GC会出发Stop The World
- 减少两处
onCreate()中的初始化操作,将部分初始化移动到IntentService中进行(IntentService在 API30 弃用) - 如果有多个进程的话,Application会初始化多次,也就是每一个进程都会走一遍Application的onCreate(),虽然其他进程初始化的Application不会影响主进程的速度,但是会影响整个手机的内存大小。所以当我们app中有多进程的时候,在onCreate中可以判断是不是主进程,之后再初始化东西
4 Activity绘制优化
- 避免xml过大,因为读取xml就已经很耗时了
- 布局层级尽量少 因为读取View的时候,是个递归操作
- View的onLayout,onMeasure,onDraw() 中 避免耗时操作
- 减少非必要的背景
5 启动页Activity的优化
- 布局优化
我们的启动页Activity包含有启动图控件、闪屏广告图控件、闪屏广告视频控件、首次安装介绍图控件。对于布局优化而言,除了启动图控件外,其他都不是App启动时都要初始化的控件,这时我们可以使用ViewStub。针对指定的业务场景,初始化指定的控件。
- 避免I/O操作
我们知道I/O操作不是实时的,例如数据库的读写、SharedPreferences#apply()。我们要注意这些操作有没阻塞主线程地执行,同时我们可以利用StrictMode严格模式,利用它可以检测我们在启动的时候有没正确进行磁盘读写操作。
- 注意图片bitmap的加载速度和编码格式
我们可以知道,启动页大部分的情况下都是图片的显示,那么我们在图片这方面怎么抠细节呢,那就是对各种第三方图片加载库的选用了Glide、Picasso、Fresco等,还有是PREFER_ARGB_8888、PREFER_RGB_565的选取问题,大家可以针对属于自己项目情况进行选取。
- 对矢量图VectorDrawable对象的使用
矢量图的核心是省时间、省空间。而对于某些用户,它的启动图可能不是一张图片,它十分简约,就一个logo,这个时候我们可以考虑一下矢量图的用法。
- 注意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=N | Trace 设备活动的 N 秒时间。若未指定该选项,命令行中,通过敲 Enter 回车键来终止 trace 进程 |
| -b N 或 - -buf-size=N | 使用 N 千字节的 trace 缓冲区大小。这个选项可以限制在 trace 期间总共收集数据的大小 |
| -k functions 或 - -ktrace=functions | Trace 指定内核方法的活动,指定于逗号分隔的列表 |
| -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) 快捷键
- 导航
| 导航操作 | 作用 |
|---|---|
| w | 放大,[+shift]速度更快 |
| s | 缩小,[+shift]速度更快 |
| a | 左移,[+shift]速度更快 |
| d | 右移,[+shift]速度更快 |
- 快捷操作
| 常用操作 | 作用 |
|---|---|
| f | 放大当前选定区域(放大选定的一块) |
| m | 标记当前选定区域(可以显示时间长度) |
| v | 高亮VSync(所在的一帧) |
| g | 切换是否显示60hz的网格线(同上) |
| 0 | 恢复trace到初始态,这里是数字0而非字母o(缩小到初始) |
| h | 切换是否显示详情 |
| / | 搜索关键字 |
| enter | 显示搜索结果,可通过← →定位搜索结果 |
| ` | 显示/隐藏脚本控制台 |
| ? | 显示帮助功能 |
每个线程有颜色表示各自不同的状态:
灰色:正在休眠。
蓝色:可运行(它可以运行,但是调度程序尚未选择让它运行)。
绿色:正在运行(调度程序认为它正在运行)。
红色:不可中断休眠(通常在内核中处于休眠锁定状态)。可以指示 I/O 负载,在调试性能问题时非常有用。
橙色:由于 I/O 负载而不可中断休眠。