如果你对本文感兴趣,也许你对我的公众号也会有兴趣,可扫下方二维码或搜索公众微信号:mxszgg
情景模拟
最近小明开源了一个 Android 三方库,接入流程很简单,开发者们只需要在应用的 Application 的 onCreate()
方法中去初始化它,然后就可以调用相应的库 API 了——
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
XiaomingLibrary.init(this);
}
}
复制代码
这是一个很常见的三方库接入后的初始化流程,但是作为库的开发者角度考虑,有没有将库的初始化流程这一步再缩减,让开发者的接入流程更简单呢?如果有的话,像 leakcanary 这种仅需要在 Application 中初始化,又并不需要调用任何 API 的库将会带给开发者一种无任何侵入式的感受。答案当然是有的,作为一个库开发者,你可以在你的库中创建一个 ContentProvider 在 ContentProvider 的 onCreate()
方法中借助 getContext()
方法返回的 Context 来完成你的库初始化,而不需要开发者们去在他们应用的 Application 的 onCreate()
方法中去初始化你的库,当然,这个 getBaseContext()
返回的 Context 的实际类型就是应用的 Application,所以可以借助该 Context 来完成库的初始化。
调用时机
那么 ContentProvider 的 onCreate()
方法是什么时候被调用的呢?它是介于 Application 的 attachBaseContext(Context)
和 onCreate()
之间所调用的,Application 的 attachBaseContext(Context)
方法被调用这就意味着 Application 的 Context 被初始化了,而 ContentProvider 拿到的 Context 也正就是 Application,所以可以在 ContentProvider 的 onCreate()
方法中完成相应的初始化操作 。口说无凭,当然要从代码的角度来证明——读者们应该都知道,在应用的启动过程中,会走到 ActivityThread 的 handleBindApplication()
方法中,在该方法中可以看到 app = makeApplication()
、installContentProviders(app)
、mInstrumentation.callApplicationOnCreate(app)
三个方法被相继调用 ——
实际上到这里源码实际上就可以解析完了,从方法名其实就可以看出 makeApplication()
是创建了 Application 并将 Application 实例赋给了 app 这个局部变量,接着 installContentProviders(app)
中会使得 ContentProvider 借助 app 这个局部变量初始化,最后 callApplicationOnCreate(app)
肯定就是调用了这个 app 的 onCreate() 方法。具体流程如下:
makeApplication()
调用链:
LoadedApk#makeApplication()
->Instrumentation#newApplication()
->Instrumentation.newApplication()
->Application#attach()
->Application#attachBaseContext()
installContentProviders()
调用链:
ActivityThread#installContentProviders()
->ActivityThread#installProvider()
->ContentProvider#attachInfo()
->ContentProvider.this.onCreate()
callApplicationOnCreate()
调用链:
Instrumentation#callApplicationOnCreate()
->Application#onCreate()
优缺点
优点很显而易见——免去了使用库的开发者们初始化库的流程,降低了接入成本,这种优势在像 leakcanary、BlockCanary 或者其他一些仅需要初始化而不需要开发者调用任何 API 的库上体现的更加明显,开发者只需要添加依赖就可以使用该库了,完全是0侵入式的接入流程。
缺点:缺点在于它并不一定适用于全部场景,因为 ContentProvider 的 onCreate()
执行在了 Application 的 onCreate()
方法之前,倘若你的库需要有其它业务的依赖(例如你的库需要在其它三方库依赖初始化完成之后才能够初始化)的话,这种方式就并不是很适配你的库。
后记
本文的内容还是十分简单的,但是笔者认为这篇文章带来的不应该仅仅是给读者一种新技能 +1 的感觉,在了解了表面现象之后,更应该去剥开表层探索实现,这样下次在跟小伙伴面前吹的时候,才能够更有底气的展现你的骚操作。最后,为了方便各位读者更好地消化内容,笔者在 github 上上传了例子,戳我直达。