如果你對本文感興趣,也許你對我的公眾號也會有興趣,可掃下方二維碼或搜尋公眾微訊號: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 上上傳了例子,戳我直達。