APP启动应用优化加速和卡顿
一:应用启动类型
- 1冷启动
应用自启动后,或系统终止应用后的首次启动
- 2暖启动
如:应用退出应用,又重新启动,程序可能已经运行,但需要重新创建acitivity。或者进程被系统杀死,但是在activity的oncreate时有savedInstanceState
- 3热启动
应用的acitvity还留在内存中,系统只需将activity带到前台
在冷启动中,应用从头开始启动。我们始终在假定冷启动的基础上进行优化。这样做也可以提升暖启动和热启动的性能。
二:启动流程分析
2.1 分析1
在冷启动开始前,系统有三个任务
- 加载并开始启动应用。(System-Fixed)
- 在启动后立即显示应用的空白启动窗口(可控),用户看到的第一个窗口(可能:透明,空白,应用主题)
- 创建应用进程(可控)
- 创建应用对象
- 创建主activity
- 走生命周期渲染界面
2.2 分析2-启动窗口的显示
对启动窗口的操作,并不会影响应用的启动速度,只是在用户交互体验上的改进;关闭启动窗口,在主题属性设置<item name = “android:windowDisablePreview”>true</item>,这样可以解决耗时应用启动白屏问题,但是可能会导致应用响应慢的问题;设置windowBackGroud主题属性<item name = “android.windowBackground”>@drawable/welcom_launch_bg</item>,让一张图片作为窗口的背景,使打开MainActivity第一眼看到的界面是一张图片而不是白屏或者黑屏。设置这个属性来显示一张背景图,还有一个效果就是启动应用程序会感觉非常快。
2.3 分析3-创建应用进程
2.4 系统和应用
在创建应用和创建Activity的过程中可能会出现性能问题。
- 当应用启动时,空白启动窗口将保留在屏幕上,直到系统首次完成应用绘制。完成后,系统进程会替换掉应用的启动窗口,允许用户开始与应用互动。
- Application创建完成后(涉及Application.oncreate的调用),进程开始根据应用生命周期阶段继续运行。
- PS:ContentProvider会影响应用启动,注意在onCreate里的任务代码
三:启动耗时检测
-
- UI显示检测
- 看ActivityManager的日志(日志过滤)
- Adb shell am start -S -W com.king.reading/.module.MainActivity
四:启动耗时分析
- 检测耗时任务
a.工具:使用Android Studio自带的CPU Profiler,可以按线程记录方法调用的耗时
b.CPU Profiler可以抓取正在运行进程的数据,如果需要抓取应用进程首次启动需要特殊处理
五:启动加速方法
- 定制初始化
对于多进程应用,如果应用又集成Application,那么oncreate方法会执行多次,针对不同进程业务,可以做业务定制的初始化。
尽量避免大量的全局静态对象,在需要的时候才创建单例,加速进程启动速度
- 异步延迟加载
不在主线程做耗时任务,如:文件操作、网络请求等,耗时任务尽量在异步线程处理
使用线程池,减少线程开销,防止多线程抢占CPU,避免UI线程时间片变短
- 系统API使用&优化布局
部分系统的API使用是阻塞性的,文件很小可能无法感知,当文件过大,或者使用频繁时,可能造成阻塞,例如SharedPreference.Editor提交操作、AssetManager.open操作
布局的复杂程度,直接影响绘制的时间,减少布局层次,无用资源使用ViewStub,使用时加载
- 任务顺序安排
通过对任务做一个顺序调整,提高CPU的使用效率,例如:不重要的Service,或其他不需要的初始化任务,延后初始化(Service是在主线程执行的)
- 将耗时的,但是没有依赖的任务提前执行,缩短启动整体耗时
六:卡顿
- 屏幕刷新机制1
- CPU负责将数据计算出来,GPU负责将界面绘制到缓冲区,Display负责将缓冲区数据展示出来
- Display每秒60帧,约16.6ms一帧,按这个频率取数据展示,同时通知CPU去准备下一页页面
- 屏幕刷新机制2
- CPU由程序的主线程控制。在收到刷新请求时,调用performTraversals里来安排一次遍历绘制View树的任务
- 同步屏障机制:我们代码发的是同步消息,界面刷新消息是异步消息,当有异步消息时,会优选执行
七:卡顿-原因
没有及时响应完view树绘制请求
- 在收到刷新请求后,主线程在处理的消息耗时严重
- 由于界面布局复杂,或无用重复计算,使即使无法完成界面数据计算
- 主线程的执行时间片太短
- 底层渲染不及时
7.1卡顿分析1
使用CPU Profiler的trace System Calls
7.2卡段分析2
使用systrace;用pythons执行Android/Sdk/platform-tools/systrace;分析UI性能,具体定位问题,还需进一步去加trace代码定位
八:卡顿加速
- 避免在主线程执行耗时操作(包含网络、文件读取、读取系统文件路径,特别是在recycler列表中),非刷新界面消息,不用主线程handler,避免增加主线程任务,同时可以加速消息处理速度。
- 优化界面布局,减少view的计算数量和重复计算次数,ListView复用item布局
- 多采用ConstraintLayout,使布局设计偏平化,减少嵌套
- 避免使用过大资源进行显示(头像使用高清图片等),避免渲染问题
- 避免开启过多的线程,导致主线程的时间片过短
- 当批量数据需要显示或修改,保证需要刷新界面的数据尽可能少