如上所见,我们可以看到在 AndroidManifest.xml 文件内定义了一个名为 WorkManagerInitializer 的 ContentProvider,我来看看 WorkManagerInitializer 里面都做了什么。
public class WorkManagerInitializer extends ContentProvider { @Override public boolean onCreate() { // Initialize WorkManager with the default configuration. WorkManager.initialize(getContext(), new Configuration.Builder().build()); return true; }
...... // 省略了没用的代码 }
如上所见其实就是在 WorkManagerInitializer 的 onCreate() 方法里面,使用默认配置初始化 WorkManager。
我们也来模仿 WorkManager 写一个 Demo,这里只贴出部分代码,更多信息查看 GitHub 上的 AppStartupSimple 下面的 ContentProvider 模块。
- 定义一个 WorkContentProvider 并在 onCreate 方法中打印一行日志。
class WorkContentProvider : ContentProvider() {
override fun onCreate(): Boolean { Log.d(TAG, "WorkContentProvider create()") return true }
..... }
- 在 AndroidManifest.xml 文件中注册 WorkContentProvider。
- 运行 App 日志如下所示。
com.hi.dhl.startup.simple D/WorkContentProvider: WorkContentProvider create()
假设你的 App 有很多类似于 WorkManager 这样的库,都在 ContentProvider 里面进行一些初始化工作,在 App 启动时运行多个 ContentProvider,这样会带来一些问题:
- 多个 ContentProvider 会增加了 App 启动运行的时间。
- ContentProvider 的 onCreate 方法会先于 Application 的 OnCreate 方法执行,这是在冷启动阶段自动运行初始化的,来看一下 Android 10 系统源码。
private void handleBindApplication(AppBindData data) { ......
if (!data.restrictedBackupMode) { if (!ArrayUtils.isEmpty(data.providers)) { // 创建ContentProvider installContentProviders(app, data.providers); } }
......
try { // 调用调用 Application 的 OnCreate 方法 mInstrumentation.callApplicationOnCreate(app); } catch (Exception e) { ...... }
...... }
这是在 App 冷启动时自动运行初始化的,这样只会增加 App 的加载时间,用户希望 App 加载得快,启动慢会带来糟糕的用户体验,AndroidX App Startup 正是为了解决这个问题而出现的。
如何正确使用 AndroidX App Startup?
使用 AndroidX App Startup 来运行所有依赖项的初始化有两种方式:
- 自动初始化。
- 手动初始化(也是延迟初始化)。
具体可以查看 GitHub 上的 AppStartupSimple 下面的 Startup-Library 模块相关代码。
自动初始化
- 在 build.gradle 文件内添加依赖。
implementation "androidx.startup:startup-runtime:1.0.0-alpha01"
- 实现 Initializer 接口,并重写两个方法,来初始化组件。
class LibaryC : Initializer<LibaryC.Dependency> { override fun create(context: Context): Dependency { // 初始化工作 Log.e(TAG, "init LibaryC ") return Dependency() }
override fun dependencies(): MutableList<Class<out Initializer<*>>> { return mutableListOf(LibaryB::class.java) } ...... }
- create(Context): 这里进行组件初始化工作。
- dependencies(): 返回需要初始化的列表,同时设置 App 启动时依赖库运行的顺序,假设
LibaryC 依赖于 LibaryB,LibaryB 依赖于 LibaryA,App 启动运行时,会先运行 LibaryA 然后运行 LibaryB 最后运行 LibaryC。
正如 GitHub 上的 AppStartupSimple 示例项目,它依赖结构就是 LibaryC 依赖于 LibaryB,LibaryB 依赖于 LibaryA,输出结果如下所示:
com.hi.dhl.startup.simple E/LibaryA: init LibaryA com.hi.dhl.startup.simple E/LibaryB: init LibaryB com.hi.dhl.startup.simple E/LibaryC: init LibaryC
- 在 AndroidManifest.xml 文件中注册 InitializationProvider。
App 启动的时 App Startup 会读取 AndroidManifest.xml 文件里面的 InitializationProvider 下面的 <meta-data> 声明要初始化的组件,完成自动初始化工作。
手动初始化(也是延迟初始化)
- 在 build.gradle 文件内添加依赖,和上文一样。
- 创建一个类 LibaryD 实现 Initializer 接口,并重写两个方法,来初始化组件,和上文一样。
- 在 AndroidManifest.xml 文件中注册 InitializationProvider。
- 禁用单个组件的自动初始化,需要在
<meta-data>标签内添加tools:node="remove"清单合并工具会将它从清单文件中删除。 - 禁用所有组件初始化,需要在
provider标签内添加tools:node="remove"清单合并工具会将它从清单文件中删除。
......
- 在需要的地方进行初始化,调用以下代码进行初始化。
AppInitializer.getInstance(context).initializeComponent(MyInitializer::class.java)
如果组件初始化之后,再次调用 AppInitializer.initializeComponent() 方法不会再次初始化。
手动初始化(也是延迟初始化)是非常有用的,组件不需要在 App 启动时运行,只需要在需要它地方运行,可以减少 App 的启动时间,提高启动速度。
全文到这里就结束了,App Startup 和 ContentProvider 相关示例已经上传到 GitHub 上了
AndroidX-Jetpack-Practice:https://github.com/hi-dhl/AndroidX-Jetpack-Practice
正在建立一个最全、最新的 AndroidX Jetpack 相关组件的实战项目 以及 相关组件原理分析文章,仓库持续更新中,可以前去查看:AndroidX-Jetpack-Practice
总结
这篇文章主要介绍了以下内容:
- ContentProvider 启动顺序源码分析。
- App Startup 是 Jetpack 的新成员,是为了解决因 App 启动时运行多个 ContentProvider 会增加 App 的启动时间的问题。
- 使用了一个 InitializationProvider 管理多个依赖项,消除了每个库单独使用 ContentProvider 成本,减少初始化时间。
- App Startup 允许你自定义组件初始化顺序。
- App Startup 可以自动初始化 AndroidManifest.xml 文件中 InitializationProvider 下面的
<meta-data>声明要初始化的组件。 - App Startup 提供了一种延迟初始化组件的方法,减少 App 初始化时间。
在 AndroidManifest.xml 文件中声明 node="remove" 打包的时候会删除?这样做的目的是什么?
- 便于管理所有的初始化项