开源库小技巧+1,在 ContentProvider 中初始化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ziwang_/article/details/82153886

如果你对本文感兴趣,也许你对我的公众号也会有兴趣,可扫下方二维码或搜索公众微信号: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 来完成你的库初始化,当然,这个 Context 的实际类型就是应用的 Application。

调用时机

那么 ContentProvider 的 onCreate() 方法是什么时候被调用的呢?它是介于 Application 的 attachBaseContext(Context)onCreate() 之间所调用的,Application 的 attachBaseContext(Context) 方法被调用这就意味着 Application 的 Context 被初始化了。简单带过一下源码,更加具体的源码解析可以参考 gityuan 的文章——

在应用的启动过程中,会走到 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()

优缺点

优点很显而易见——免去了使用库的开发者们初始化库的流程,降低了接入成本,这种优势在像 leakcanaryBlockCanary 或者其他一些仅需要初始化而不需要开发者调用任何 API 的库上体现的更加明显,开发者只需要添加依赖就可以使用该库了,完全是0侵入式的接入流程。

缺点:缺点在于它并不一定适用于全部场景,因为 ContentProvider 的 onCreate() 执行在了 Application 的 onCreate() 方法之前,倘若你的库需要有其它业务的依赖(例如你的库需要在其它三方库依赖初始化完成之后才能够初始化)的话,这种方式就并不是很适配你的库。

后记

本文的内容还是十分简单的,但是笔者认为这篇文章带来的不应该仅仅是给读者一种新技能 +1 的感觉,在了解了表面现象之后,更应该去剥开表层探索实现,这样下次在跟小伙伴面前吹的时候,才能够更有底气的展现你的骚操作。最后,为了方便各位读者更好地消化内容,笔者在 github 上上传了例子,戳我直达

阅读更多

没有更多推荐了,返回首页