一个应用App的启动速度能够影响用户的首次体验,通常用户期望app响应和加载速度越快越好。一个启动速度慢的app很可能会给用户留下不好的印象,除了导致用户在应用市场上的打分低之外,很有可能导致致用户直接卸载。这种糟糕的体验可能会导致用户在应用商店针对您的应用给出很低的评分,甚至完全弃用您的应用。
APP启动优化
关于APP启动优化
- 启动分类
- 冷启动: 耗时最多,衡量标准 Click Event -> IPC -> Process.start -> ActivityThread -> bindApplication -> LifeCycle -> ViewRootImpl
- 热启动 最快 后台 -> 前台
- 温启动 较快 LifeCycle 它只会重走Activity的声明周期,而不会再进行进程的创建、Application的创建等。
冷启动之前
- 启动APP
- 加载空白Window
- 创建进程 冷启动之前的行为时系统的行为,我们是没有办法干预的。
随后任务
- 创建Application
- 启动主线程
- 创建MainActivity
- 加载布局
- 布置屏幕
- 首帧绘制
- 优化方向
- Application和Activity生命周期
启动时间测量方式
- adb命令 adb shell am start -W packagename/(包名)首屏Activity 相关输出:
- ThisTime:最后一个Activity启动耗时
- TotalTime:所有Activity启动耗时
- WaitTime:AMS启动Activity的总耗时
adb命令方式:线下使用方便,但是不能带到线上,而且非严谨精确时间。
- 手动打点 启动时埋点,启动结束埋点,二者差值。 误区:onWindowFocusChanged只是首帧时间。 正解:真实数据展示。 手动打点方式:精确,可带到线上使用,注意避开误区选择数据真正显示作为测量时间点。addOnDrawListener。
启动优化工具
- traceview 图形形式展示执行时间、调用栈等等。信息全面,包含所有线程。 Debug.startMethodTracing(“文件名”); Debug.stopMethodTracing(); 生成文件存放在sd卡:Android/data/packagename/files traceview工具运行时开销严重,整体都会变慢。可能会带偏优化方向。
- systrace 结合Android内核数据,声明html报告,在API18以上使用,推荐向下兼容的TraceCompact。 轻量级,开销小;能直观反映CPU利用率。
获取方法耗时
- 常规方式:侵入性强,工作量大。
- AOP方式(Aspect Oriented Programming,面向切面编程):针对同一类问题的统一处理。无侵入添加代码。 AspectJ的使用。
异步优化
- 优化技巧:Theme切换,感觉上的块。
- 异步优化思想:子线程分担主线程任务,并行减少时间。
- 注意事项: 一部分代码不符合异步要求 需要在某阶段完成 区分CPU密集型和IO密集型任务。
异步初始化
- 常规异步痛点 代码不优雅 场景不好处理(依赖关系) 维护成本高
- 启动器 核心思想:充分利用CPU多核,自动梳理任务顺序。 启动流程:代码Task话,启动逻辑抽象为Task。根据所有任务的依赖关系,排序生成一个有向无环图。多线程按照排序后的优先级依次执行。
优化实战
1、布局优化
2、逻辑优化
- 必要且耗时的逻辑,考虑单独开线程执行
- 必要不耗时,按优先级高低依次执行
- 非必要的延迟初始化,等用到再初始化
3、针对冷启动的欺骗效果
使用 placeholder UI
Android 最新的 Material Design 建议使用一个 placeholder UI 来展示给用户直至 App 加载完毕,类似 iOS 的做法。
自定义主题,设置 windowBackground 属性,给 Window 加上背景。
<style name="SplashTheme" parent="AppTheme">
<item name="android:windowBackground">@drawable/logo_splash</item>
</style>
先加载一个不渲染布局的 Activity 作为启动屏
写一个什么都不做的 LogoSplashActivity
public class LogoSplashActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 这里并没有 setContentView,单纯只是用来跳转到相应的 Activity
// 目的是减少首屏渲染
if (AppPref.isFirstRunning(this)) {
IntroduceActivity.launch(this);
} else {
MainActivity.launch(this);
}
finish();
}
}
在 AndroidManifest.xml 中设置其为启动屏,并加上主题
<activity
android:name=".ui.module.main.LogoSplashActivity"
android:screenOrientation="portrait"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
这样启动屏显示 LogoSplashActivity,本身不渲染布局,显示主题设置的 placehold UI 背景。
文本是对Android开发工作中的APP启动优化的简单解析,APP启动优化的方案有很多,更多进阶性能优化的技术笔记可参考《Android性能优化笔记》点击可以查看详细性能优化类目。