PicassoProvider初始化時機
Picasso版本:
// picasso
implementation 'com.squareup.picasso:picasso:2.71828'
在學習Picasso源碼的過程中,發現了Picasso對象的初始化不需要傳入上下文對象了,示例代碼如下:
// 加載網絡圖片
Picasso.get()
.load("xxx")
.into(iv1);
我們可以通過Picasso.get()
方法直接獲取Picasso的對象。
Picasso.get()源碼
那么它到底需不需要context對象呢?我們點進去看一下。
@SuppressLint("StaticFieldLeak")
static volatile Picasso singleton = null;
...
public static Picasso get() {
if (singleton == null) {
synchronized (Picasso.class) {
if (singleton == null) {
if (PicassoProvider.context == null) {
throw new IllegalStateException("context == null");
}
singleton = new Builder(PicassoProvider.context).build();
}
}
}
return singleton;
}
我們可以看到,Picasso使用的是單例模式,是典型的DCL(Double-checked-locking)——雙重檢查鎖模式
。
Picasso對象singleton的最終初始化時通過給Picasso.Builder
構造方法傳入一個PicassoProvider.context
參數,然后調用Picasso.Builder#build()
方法完成Picasso
對象的構建。
這說明Picasso還是需要Context對象的,只不過不需要用戶傳入。
Picasso.Builder
我們看下Picasso.Builder的實現:
/** Start building a new {@link Picasso} instance. */
public Builder(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("Context must not be null.");
}
this.context = context.getApplicationContext();
}
這里可以明顯的看出,我們傳入的PicassoProvider.context
參數就是Context
類型,那么它是何時初始化的呢?
PicassoProvider
我們看下PicassoProvider的實現:
@RestrictTo(LIBRARY)
public final class PicassoProvider extends ContentProvider {
@SuppressLint("StaticFieldLeak") static Context context;
@Override public boolean onCreate() {
context = getContext();
return true;
}
@Nullable @Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
@Nullable @Override public String getType(@NonNull Uri uri) {
return null;
}
@Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override public int delete(@NonNull Uri uri, @Nullable String selection,
@Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
@Nullable String[] selectionArgs) {
return 0;
}
}
PicassoProvider繼承自ContentProvider,PicassoProvider唯一的作用是在onCreate方法內部初始化了PicassoProvider.context成員變量
,PicassoProvider中的其他方法都是默認實現。
我們知道ContentProvider是在Activity之前啟動的,具體調用順序為Application#attachBaseContext --> ContentProvider#onCreate --> Application#onCreate --> Activity#onCreate
,所以我們在Activity中調用Picasso.get時,PicassoProvider.context早已初始化好了,我們就不必擔心PicassoProvider.context賦值的問題。
我們知道,在正常使用ContentProvider時,還需要在AndroidManifest.xml中注冊。我們找下注冊的位置。
很明顯,在使用Picasso時我們是不需要在AndroidManifest.xml中注冊的,那么PicassoProvider就肯定是注冊在picasso的aar文件中的AndroidManifest.xml中了。
這里我們在Project視圖下,打開External Libraries目錄,找到picasso依賴文件,如下所示:
比較疑惑的是,這里的Gradle依賴的是aar文件,我們應該是可以看到aar文件中的非java文件的,不過這里只顯示了classes.jar
包。
這樣就只能找到我們的aar源文件查看了。右鍵我們Picasso的Gradle依賴,選擇Library Properties...
選項,在彈出的對話框中就可以看到aar的源文件了。
我們按圖索驥,先找到這個jar文件的目錄,目錄如下:
雖然找到這個了,不過依然沒什么用,我們想要的是aar文件。我們看下上面的文件夾:
這個就是我們要找的aar文件。
查看aar文件的內容
我們先復制一份aar文件出來,然后將后綴改為.zip
,接著解壓該文件,解壓后如下所示:
可以看到我們想找的AndroidManifest.xml,看下內容:
可以看到,PicassoProvider也注冊到AndroidManifest.xml中了,至此Picasso中的context的獲取原理搞清楚了。