参考:
A
B
我们做项目的时候会用到很多库,不论是三方库还是或者是自己写的,不可避免的会要去初始化它们,一般都是在Application的oncreate里,那么我们现在会在Application里这么写:
@Override
public void onCreate() {
super.onCreate();
MyLib.init(this);
}
通过init方法传递一个Application进去并持有它。
这样做没什么错,但是在我看来是不太好的。
如果你使用过Lifecycle或者Firebase,你会发现你根本不用写哪怕一行的初始化代码就可以使用它,那么它们是怎么做的呢?
以Lifecycle为例:
我们去看Lifecycle的Manifest,其中会注册一个ContentProvider:
<provider
android:name="android.arch.lifecycle.LifecycleRuntimeTrojanProvider"
android:authorities="xx.xx.xxxx.lifecycle-trojan"
android:exported="false"
android:multiprocess="true" />
而这个Provider的实现非常的简单:
public class LifecycleRuntimeTrojanProvider extends ContentProvider {
@Override
public boolean onCreate() {
LifecycleDispatcher.init(getContext());
ProcessLifecycleOwner.init(getContext());
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, String[] strings, String s, String[] strings1,
String s1) {
return null;
}
...
//return null or 0;
}
原理:我们都知道ContentProvider的onCreate的调用时机介于Application的attachBaseContext和onCreate之间,Provider的onCreate优先于Application的onCreate执行,并且此时的Application已经创建成功,而Provider里的context正是Application的对象,Lifecycle这么做,把init的逻辑放到库内部,让调用方完全不需要在Application里去进行初始化了,十分方便。
注意点:
使用ContentProvider初始化的方式,我们需要注意一下几点:
首先,在Manifest里设置ContentProvider的时候要设置一个authorities,这个authorities相当于ContentProvider的标识,是不能重复的,为了保证不重复,我们再设置这个值的时候最好不要硬编码,而是使用以下的这种方式:使用appid+xxx
<provider
android:authorities="${applicationId}.xxprovider"
android:name=".MyLibRuntimeProvider"
android:exported="false"/>
由ActivityThread的handleBindApplication方法可以看到,是先调用installContentProviders方法,然后调用mInstrumentation.callApplicationOnCreate方法的。