原文: Your android libraries should not ask for an application context
做者:florent champigny@Idean
Markdown:原文 | 譯文html
一般來講,當咱們引入一個第三方庫,第一件要作的事情是在Application
中的onCreate
傳入context
初始化這個庫 😞。可是爲何像一些庫如Firebase
🔥,初始化的時候並不須要在Application
中初始化呢?今天咱們就來探索一下這個問題 🧐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
若是你的項目加入了Firebase 🔥, 你會發現它並無要求初始化, 你只要使用它 :
less
這個數據庫訪問沒有須要context
的傳入,經過離線訪問存儲本地。能夠猜想它有一個機制獲取上下文application context
,自動完成初始化。ide
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(…)
複製代碼
若是一些庫沒有使用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
沒想到你們討論這麼厲害,感謝你們,學到不少。這裏我找到了Firebase
關於這種初始化方法的原文
How does Firebase initialize on Android?
看最後一段,做者對這種「濫用」ContentProvider
表達了本身對觀點
ContentProvider的此特定應用程序看起來確實很奇怪,由於它實際上並未提供任何內容。 而且您必須經過返回null提供全部其餘ContentProvider必需方法的實現。 可是,事實證實,這是自動初始化而無需額外代碼的最可靠方法。 我認爲,使用Firebase爲開發人員帶來的便利遠遠超過了對ContentProvider使用這種奇怪之處的彌補。 Firebase就是關於易於使用的東西,沒有什麼比沒有代碼更容易了!