我们做项目的时候会用到很多库,不论是三方库还是二方库,又或者是自己写的,不可避免的会要去初始化它们,一方面是因为库中会需要使用Context进行一些操作,比如startActivity,又或者getResource;另一方面在初始化的时候我们可以传递一些缺省值给对应的库。如果你的库在初始化的时候只需要传递一个Context(例如前面提到的Lifecycle又或者是Firebase),那么我们现在会在Application里这么写:
@Override public void onCreate() { super.onCreate(); MyLib.init(this); }
通过init方法传递一个Application进去并持有它。
这样做没什么错,但是在我看来是不太好的。一方面如果使用者忘记初始化它了,很可能会出现NPE(我之前就犯过这种错误,简直想撞墙);另一方面,当你需要初始化十几二十个库的时候,代码就会变得比较庞大了。
但是如果你使用过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; } @Nullable @Override public String getType(@NonNull Uri uri) { return null; } @Nullable @Override public Uri insert(@NonNull Uri uri, ContentValues contentValues) { return null; } @Override public int delete(@NonNull Uri uri, String s, String[] strings) { return 0; } @Override public int update(@NonNull Uri uri, ContentValues contentValues, String s, String[] strings) { return 0; } }
可以看到除了onCreate,其他的方法都没有逻辑,而onCreate里的逻辑也十分简单,就是去进行Lifecycle的初始化。
注意点
使用ContentProvider初始化的方式,我们需要注意一下几点:
首先,在Manifest里设置ContentProvider的时候要设置一个authorities,这个authorities相当于ContentProvider的标识,是不能重复的,为了保证不重复,我们再设置这个值的时候最好不要硬编码,而是使用以下的这种方式:
<provider android:authorities="${applicationId}.cp" android:name=".MyLibRuntimeProvider" android:exported="false"/>
使用gradle的placeholder,可以比较有效的避免重复,Lifecycle就是这么做的。
其次,如果你的App的多进程架构的,可以将multiprocess设置成true,以保证每一个进程都会初始化该ContentProvider:
最后,如果你的App使用到了Application替换技术,可能是hotpatch,也可能是dex加壳等等,需要注意你的ProxyApplication的代码,因为这个时候在ContentProvider中getContext()获得的是你的ProxyApplication,而不是App真正的Application。
原网站:http://zjutkz.net/2017/09/11/一个小技巧——使用ContentProvider初始化你的Library/index.html