作者:王晨彦
一、前言
我们在开发应用的时候,一般都会引入 SDK,而大部分 SDK 都要求我们在 Application 中初始化,当我们引入的 SDK 越来越多,就会出现 Application 越来越长,如果 SDK 的初始化任务相互依赖,还要处理很多条件判断,这时,如果再来个异步初始化,相信大家都会崩溃。
有人可能会说,我都在主线程按顺序初始化不就行了,当然行,只要老板不来找你麻烦。
「小王啊,咱们的 APP 启动时间怎么这么久?」
开个玩笑,可见,一个优秀的启动框架对于 APP 启动性能而言,是多么的重要!
二、为什么不用 Google 的 StartUp?
说到启动框架,就不得不提 StartUp,毕竟是 Google 官方出品,现有的启动框架,或多或少都有参考 StartUp,这里不再详细介绍,如果对 StartUp 还不了解,可以参考这篇文章 Jetpack系列之App Startup从入门到出家。
https://juejin.cn/post/7023643365048582174
StartUp 提供了简便的依赖任务初始化功能,但是对于一个复杂项目来说,StartUp 有以下不足:
1. 不支持异步任务
如果通过 ContentProvider 启动,所有任务都在主线程执行,如果通过接口启动,所有任务都在同一个线程执行。
2. 不支持组件化
通过 Class 指定依赖任务,需要引用依赖的模块。
3. 不支持多进程
无法单独配置任务需要执行的进程。
4. 不支持启动优先级
虽然可以通过指定依赖来设置优先级,但是过于复杂。
三、一个合格的启动框架是怎么样的?
1. 支持异步任务
减少启动时间的有效手段。
2. 支持组件化
其实就是解耦,一方面是解耦任务依赖,另一方面是解耦 app 和 module 的依赖。
3. 支持任务依赖
可以简化我们的任务调度。
4. 支持优先级
在没有依赖的情况下,允许任务优先执行。
5. 支持多进程
只在需要的进程中执行初始化任务,可以减轻系统负载,侧面提升 APP 启动速度。
四、收集任务
如果要做到完全解耦,我们可以使用 APT 收集任务。
首先定义注解,即任务的一些属性。
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class InitTask(
/**
* 任务名称,需唯一
*/
val name: String,
/**
* 是否在后台线程执行
*/
val background: Boolean = false,
/**
* 优先级,越小优先级越高
*/
val priority: Int = PRIORITY_NORM,
/**
* 任务执行进程,支持主进程、非主进程、所有进程、:xxx、特定进程名
*/
val process: Array<String> = [PROCESS_ALL],
/**
* 依赖的任务
*/
val depends: Array<String> = []
)
name 作为任务唯一标识,类型为 String 主要是解耦任务依赖。
background 即是否后台执行。
priority 是在主线程、无依赖场景下的执行顺序。
process 指定了任务执行的进程,支持主进程、非主进程、所有进程、:xxx、特定进程名。
depends 指定依赖的任务。
<