Jetpack之—App Startup
官方的定义
App Startup库提供了一种在应用程序启动时初始化组件的简单、高效的方法。库开发人员和应用程序开发人员都可以使用App Startup来简化启动顺序并明确设置初始化顺序。App Startup库允许您定义共享单个内容提供程序的组件初始化程序,而不是为您需要初始化的每个组件定义单独的内容提供程序。这可以显着改善应用程序启动时间。
为什么App Startup可以改善应用程序的启动时间呢?
这里就要延伸一下我们一般初始化sdk的方式:
在自定义
Appliaction
的onCreate()
方法中初始化sdk,它缺点就是开发者手动调用,优点就是可以自己控制调用时机(这点在国内开发市场很重要哈,现在国内应用市场必须要求用户同意后才能做sdk初始化)
:
class LiteApp : Application(){
override fun onCreate() {
super.onCreate()
TsApp.get().init(this)
}
}
在自定义
ContentProvider
的onCreate()
中初始化库,这种方式可能不少同学没有用过或者听说过,毕竟我们对于ContentProvider
的了解不就是个内容提供者吗?其实,如果大家如果有用过谷歌的Firebase
库就知道,使用这个库不用我们自己调用初始化方法就能实现数据分析的上传,其实它就是借用了ContentProvider
实现自动调用初始化接口。
ContentProvider
的执行时机:
ContentProvider
的onCreate()
方法是在Appliaction的onCreate()
方法之前执行,并且ContentProvider
也是四大组件之一,我们可以拿到Context,这里也要记得在AndroidManifest.xml文件中注册一下:
<provider
android:name=".CustomProvider"
android:authorities="${applicationId}.customProvider"
android:exported="false" />
authorities
属性没有规定的值,但要保证在整个手机里面的app中是唯一的,以防止和其他应用相冲突。
ContentProvider初始化的优缺点
通过ContentProvider
初始化的优点很明显就是不用开发者主动调用sdk的初始化方法,而且初始化比在Application更提前了一点。缺点也很明显,就是增加了额外的耗时消耗,毕竟ContentProvider
作为一个四大组件来说还是有不少开销的,如果每个库都搞一个ContentProvider
来初始化的话那相当于开了很多Activity一样,这必然会造成较大的耗时开销:
这是网上找到的一张Google官方给出一个ContentProvider
耗时的测试结果,它的这种情况是在空的ContentProvider
情况下耗时2ms,当我们在每个ContentProvider
里面还有sdk初始化的操作,还有很多个ContentProvider
时,这个耗时绝对是值得起重视的,甚至会大大降低了App的启动速度。
那如何解决这个痛点呢?
这就得使用:App Startup
。既然是解决,那就是App Startup
库可以将所有sdk的初始化用一个ContentProvider
来完成,并提高App的启动速度。App Startup库的内部实现了一个ContentProvider
,并提供操作标准的方法给开发者,所以对于第三方库来说就不用实现额外的ContentProvider
了。当然,这里不能解决的是已经使用ContentProvider
进行初始化的第三方库。
App Startup库的使用
添加依赖
dependencies {
implementation "androidx.startup:startup-runtime:1.1.0-beta01"
}
实现App Startup库的Initializer接口
先创建一个SdkSample模拟sdk,并提供一个init方法:
object SdkSample{
fun init(context: Context){
}
}
实现Initializer
接口
class CustomInitializer:Initializer<Unit> {
override fun create(context: Context) {
SdkSample.init(context)
}
override fun dependencies(): MutableList<Class<out Initializer<*>>> {
return mutableListOf()
}
}
create()
方法显而易见就是sdk初始化的地方,它提供初始化所需的Context
;dependencies()
方法表示CustomInitializer
是否还需要依赖于其他的Initializer
,一般情况下这里都是直接返回空list就行。如果有的话,就在这里进行配置,App Startup会先初始化依赖的Initializer,然后才会初始化当前的CustomInitializer
。看下面代码:
class CustomInitializer:Initializer<Unit> {
override fun create(context: Context) {
SdkSample.init(context)
}
override fun dependencies(): MutableList<Class<out Initializer<*>>> {
return mutableListOf(FirstInitializer::class.java)
}
}
//先初始化的FirstInitializer
class FirstInitializer:Initializer<Unit> {
override fun create(context: Context) {
SdkSample.init(context)
}
override fun dependencies(): MutableList<Class<out Initializer<*>>> {
return mutableListOf()
}
}
这个时候CustomInitializer
只有在FirstInitializer
初始化完了才会开始初始化。
将CustomInitializer配置到AndroidManifest
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="com.qisan.myapplication.CustomInitializer"
android:value="androidx.startup" />
</provider>
这个配置里面只有name
这个属性是我们能改的,其他都是固定配置,保持这样Startup
库才能正常使用。
对于CustomInitializer
需要依赖其他Initializer
初始化完成才执行的情况,CustomInitializer
可以不被声明,只声明FirstInitializer
就行了:
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="com.qisan.myapplication.FirstInitializer"
android:value="androidx.startup" />
</provider>
到这里,App Startup库的使用就完成了,很简单,三步即可使用:
依赖App Startup的库;
实现一个Initializer;
把实现的Initializer配置到AndroidManifest.xml。
Initializer的动态加载
Initializer
都会在App启动时自动执行初始化,但是作为开发者有时候是不需要启动就初始化的,尤其是现在国内应用市场的审核机制,最好在用户同意了你的隐私协议和服务协议才开始初始化,如果你的sdk初始化有涉及http请求或者其他权限,审核的时候都会被驳回来的。要实现动态加载,首先我们要让Initializer
不会自动执行,这个时候主要在meta-data
标签中加入 tools:node="remove"
即可:
<provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <meta-data android:name="com.qisan.myapplication.CustomInitializer" android:value="androidx.startup" tools:node="remove"/> </provider>
加上这个节点后在打包成APK时会把所有android:name
是com.qisan.myapplication.CustomInitializer
的meta-data节点全部删除,这样就无法自动初始化了,要在合适的时机初始化只要调用即可:
AppInitializer.getInstance(this).initializeComponent(CustomInitializer::class.java) 复制代码