Android Architecture Component - App Startup

App Startup 是 Jetpack 提供的一个用于 App 启动时进行 component 初始化的机制,那么先来看看我们之前一般都是如何实现初始化的。

1. Before Startup

最直观的用于初始化 component 的地方,肯定是 Application 的 onCreate 方法了,相信也都写过不少这样的代码:

 1// FooApp.kt
 2
 3override fun onCreate() {
 4    super.onCreate()
 5
 6    // Timber
 7    Timber.plant(Timber.DebugTree())
 8    // Litho
 9    SoLoader.init(this, false)
10}

这种方式比较简单,也只用写一遍,但不好的地方也显而易见:

  1. 写的这唯一一遍,要么是一开始就照着 doc 粘贴的,要么就是遇到了 crash 才想起来漏了这么个地方
  2. 对于 library 而言,普通 App 开发者算是用户了,要求用户在合适的地方为 library 做初始化,感觉你这 library 是有点不太省心吧
  3. 对于 App 而言,这种初始化方式,在代码职责分工的角度,也显得比较有侵略性。为啥你的初始化要放我的 Application 里?

还有另一种方式,我们知道 ContentProvider 的 onCreate 方法会在 Application 的 onCreate 之前调用,在这儿做初始化好像也比较合适?

这种方式相比上面的 Application 是要自由一些的,毕竟开发者可以不用再去关心那么多 library 的初始化问题了。

但是万事皆有代价,相比单一的注入场景,ContentProvider 确实分工明确了一些,各 library 关心自己的初始化就行。但是一方面 ContentProvider 的 onCreate 也是在 UI 线程调用的,另一方面 ContentProvider 的初始化也比较重,人家怎么说也是「四大组件」之一吧?

相比在 Application 中做初始化,ContentProvider 更自由,同时也缺少了约束。想想在 Application 打开的瞬间,若干个 ContentProvider 一起在 UI 线程初始化不同的 library,启动时间当然不会好看了。


2. App Startup

所以 Google 引入了 App Startup,一方面使用一个中心化的 ContentProvider 做初始化,另一方面,使用 Initializer 这样一个 Contract 做具体的初始化工作,分工明确一些。如果不同的 component 有依赖,也会按照依赖初始化每个 component,并保证只会初始化一次。

具体使用参考 Doc 就行:App Startup Guide

不过 Doc 中的例子中,因为 WorkManager 是会在 App 启动时,自动初始化的,所以此处需要手动在 manifest 文件中禁用初始化。

这可能是我看过的最简单的源码了,主要逻辑都在 200 行的 AppInitializer 里面。


3. 真的有用?

相比于之前的方案:

  1. 因为有了一个中心化的 ContentProvider,所以不用再为了初始化创建多个了。

    但是,即使按照之前的方式,我也可以在一个 ContentProvider 里做所有的初始化呀。

  2. 因为引入了 component 的依赖,初始化的职责划分可以更明确一些。

    但是,我也可以手动创建多个类,每一个里面去做具体的初始化呀。

它所做的,仍然是以同步 blocking 的方式,在 UI 线程做同样多的初始化。

所以,在我看来,这只是把之前的方式,做了一个标准化而已。

既然定义了这个用来做初始化的 ContentProvider,那就用这一个;

既然定义了 Initializer 这个 Contract 负责初始化,那就都用这个。

常听到的话说,「如果一个 library 的功能,花一个下午就能实现,那就没必要引入新的依赖了。」

所以是有点遗憾,期待后续更新,能覆盖更多场景吧~