【譯】你的Android庫是否還在Application中初始化?

原文: Your android libraries should not ask for an application context
做者:florent champigny@Idean
Markdown:原文 | 譯文html

一般來講,當咱們引入一個第三方庫,第一件要作的事情是在Application中的onCreate傳入context初始化這個庫 😞。可是爲何像一些庫如Firebase🔥,初始化的時候並不須要在Application中初始化呢?今天咱們就來探索一下這個問題 🧐android

Android庫的初始化

舉個栗子,咱們須要在app中國呢使用ARouter,在使用前須要初始化傳入context,所以若是沒有application時咱們要建立一個:git

class MainApplication : Application() {
    override fun onCreate(){
        super.onCreate()
        ARouter.init(mApplication); 
    }
}
複製代碼

而後要在清單文件 AndroidManifest.xml 中聲明纔會執行 :github

<application android:name=".MainApplication" ... 複製代碼

更多庫怎麼辦

如今想象咱們使用了ARouter,友盟統計,Realm,ToastUtils等庫時,咱們的application可能會是以下形式:數據庫

class MainApplication : Application() {
    override fun onCreate(){
        super.onCreate()
        ARouter.init(this)
        UMConfigure.init(this,...)
        Realm.init(this)
        ToastUtils.init(this)
    }
}
複製代碼

在項目中, 僅僅爲了初始化一些庫,我就必須得新建Application而且在onCreate中調用它。(譯者:也許你認爲這也沒什麼,可是若是你本身建立了多個庫須要context時,你每次得預留一個init方法暴露給調用者,使用時又得在application初始化。)app

Useless

無需「初始化」的庫

若是你的項目加入了Firebase 🔥, 你會發現它並無要求初始化, 你只要使用它 :
less

這個數據庫訪問沒有須要context的傳入,經過離線訪問存儲本地。能夠猜想它有一個機制獲取上下文application context,自動完成初始化。ide

ContentProvider & Manifest-Merger

developer.android.com/studio/buil…gradle

你的Apk文件只包含一個清單文件AndroidManifest.xml,可是你的Android Studio項目可能會有多個源集(main source set),構建變體(build variants),導入的庫(imported libraries)構成。所以在編譯構建app時,gradle插件會將多個manifest文件合併到一個清單文件中去。ui

咱們能夠看下合併後的清單文件(目錄以下):

app/build/intermediates/merged_manifests/MY_APP/processMY_APPDebugManifest/merged/AndroidManifest.xml

咱們能夠發現一個關於Firebase庫的provider被引入到清單文件中:

使用Android Studio點擊打開FirebaseInitProvider, 咱們知道了這個provider經過this.getContext()來訪問上下文。
內容提供者ContentsProviders會直接在Application建立後完成初始化,所以經過它來完成library的初始化不失爲一個好辦法。

自動初始化咱們的庫

若是咱們自定義了ToastUtils庫須要初始化,咱們本身提供一個Provider :

class ToastInitProvider : ContentProvider() {

    override fun onCreate(): Boolean {
        ToastUtils.init(context)
        return true
    }
    ...
}
複製代碼

而後這個庫中的AndroidManifest.xml中加入它

<provider android:name=".ToastInitProvider" android:authorities="xxx.xx.ToastInitProvider" />
複製代碼

而後當咱們使用這個ToastUtils庫時,無需添加額外的代碼在項目中初始化它😎,直接使用它便可:

ToastUtils.show("this is toast")
複製代碼
Stetho.getInstance().configure(…)
複製代碼

刪除Application

若是一些庫沒有使用InitProviders,咱們能夠建立它:

class ARouterInitProvider : ContentProvider() {

    override fun onCreate(): Boolean {
        ARouter.init(this)
        return true
    }
    ...
}
class RealmInitProvider : ContentProvider() {

    override fun onCreate(): Boolean {
        Realm.init(this)
        return true
    }
    ...
}
複製代碼

而後加入到清單文件AndroidManifest中 :

<provider android:name=".ARouterInitProvider" android:authorities="${applicationId}.ARouterInitProvider" />
<provider android:name=".RealmInitProvider" android:authorities="${applicationId}.RealmInitProvider" />
複製代碼

如今咱們能夠 移除 這個 MainApplication

Happy Dance

項目地址

github.com/florent37/A…

補充說明

沒想到你們討論這麼厲害,感謝你們,學到不少。這裏我找到了Firebase關於這種初始化方法的原文

How does Firebase initialize on Android?

看最後一段,做者對這種「濫用」ContentProvider表達了本身對觀點

ContentProvider的此特定應用程序看起來確實很奇怪,由於它實際上並未提供任何內容。 而且您必須經過返回null提供全部其餘ContentProvider必需方法的實現。 可是,事實證實,這是自動初始化而無需額外代碼的最可靠方法。 我認爲,使用Firebase爲開發人員帶來的便利遠遠超過了對ContentProvider使用這種奇怪之處的彌補。 Firebase就是關於易於使用的東西,沒有什麼比沒有代碼更容易了!

相關文章
相關標籤/搜索