引入原因(背景)
用过 LeakCanary 的同学都知道,早期的 LeakCanary 引入的时候需要引入两个包 一个 debug 的 和一个 release 的空实现库,而新版的不需要
早期版本需要是因为应用要在 Application 的 onCreate 中调用 LeakCanary 的 install 方法来安装,以便 LeakCanary 正常工作。如果不引入,在编 release 包时会报错:
if (!LeakCanary.isInAnalyzerProcess(this)) { LeakCanary.install(this); }
新版只需要在debug中引入 LeakCanary 即可,无需再引入空实现的库,因为在新版的 LeakCanary 中无需再去调用 LeakCanary 的任何代码即可让其正常工作,实现这个效果通过的就是 ContentProvider
ContentProvider Android四大组件使用的较少的组件,主要功能是应用间的数据共享,LeakCanary 在这里用到的却并不是这个功能,而只是它生命周期的一部分。
在应用启动时的调用顺序:
Application.attachBaseContext -> ContentProvider.onCreate -> Application.onCreate
而应用中通常是在
Application.onCreate
中对引入的库进行初始化,那如果库将自己的初始化置于ContentProvider.onCreate
中,应用在引入的时候无需初始化,又能保证在使用库的时候库已经完成了初始化,一举两得,LeakCanary 就是这么做的:internal sealed class AppWatcherInstaller : ContentProvider() { ... override fun onCreate(): Boolean { val application = context!!.applicationContext as Application InternalAppWatcher.install(application) return true } ... }
<application> <provider android:name="leakcanary.internal.AppWatcherInstaller$MainProcess" android:authorities="${applicationId}.leakcanary-installer" android:exported="false" /> </application>
如此便实现了库自动初始化的效果,这种巧妙的方案有啥缺点不呢?
因为 ContentProvider 属于四大组件之一,属于重量级了,google 官方给出的测试结果:在一台搭载Android 10系统的Pixel2手机上一个空的ContentProvider大约会占用2ms的耗时,随着ContentProvider的增加,耗时也会跟着一起增加。如果你的应用程序中使用了50个ContentProvider,那么将会占用接近20ms的耗时。
这么看来这种方案虽然简化了库接入着的操作,却增加了珍贵的启动时长,为了解决这个问题,引入了 Startup
Startup 虽然同样是使用 ContentProvider 来进行库的初始化,但是会将应用中所有接入了Startup 的库的操作通过
<provider> <meta-data>
合并到一个 ContentProvider 中进行初始化。
使用方式
包引入
dependencies { implementation "androidx.startup:startup-runtime:1.0.0-alpha01" }
定义初始化方法 UtilInitializer
class UtilInitializer: Initializer<Unit> { override fun create(context: Context) { // 当前库的初始化方法调用 AppContextUtil.getInstance().init(context) } override fun dependencies(): MutableList<Class<out Initializer<*>>> { // 依赖需要提前初始化的库 return mutableListOf() } }
AndroidManifest 配置
<provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <meta-data android:name="自定义的Initializer" android:value="androidx.startup" /> </provider>
兼容性
每个项目对于库要求的初始化时机可能不同,当应用需要对某个库进行手动初始化时,需要在项目的 AndroidManifest 中对指定的库
tools:node="remove"
来移除他的自动初始化<provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <meta-data android:name="需要手动初始化的库的Initializer" tools:node="remove" /> </provider>
在需要手动初始化的地方调用
AppInitializer.getInstance(context).initializeComponent(UtilInitializer::class.java)
即可