Android Glide4.0 原始碼遨遊記(第一集)

Glide
前言
Android中載入圖片的形式有很多種,網上也有很多的知名圖片載入庫,例如Glide、Picasso、Fresco等等,它們為我們帶來的方便就不需再多言了,無論是從載入到快取還是佔位圖等等都提供了簡易的Api,且實現強大的功能。本系列只針對 Glide4.0 版本原始碼進行分析,提高自身閱讀原始碼的能力,同時也是為了瞭解其中載入的流程以及快取的原理,本文儘可能地截圖說明結合原始碼解析,如有疏忽之處,還請指教。
關於作者
一個在奮鬥路上的Android小生,歡迎關注,互相交流
GitHub: GitHub-ZJYWidget
CSDN部落格: IT_ZJYANG
簡 書: Android小Y
片頭(Glide的基本使用)
1.首先肯定是新增依賴:
dependencies { compile 'com.github.bumptech.glide:glide:4.6.1' annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1' }
2.流式呼叫,一行程式碼實現載入:
//載入本地資源 Glide.with(context).load(R.drawable.ic_android).into(imageView); //載入網路圖 Glide.with(context).load("http://....").into(imageView); //裁剪為圓形 Glide.with(context).load(R.drawable.ic_android).apply(RequestOptions.bitmapTransform(new CircleCrop())).into(imageView);
呼叫幾個api就能輕易實現我們想要的效果,更多用法詳見 Glide使用文件
劇情(Glide.with 糧草先行)
由於3.0版本和4.0版本稍有差別,本文以4.0進行分析,Glide表面上簡潔的呼叫,背後隱藏了很多的模組和複雜的邏輯,不然也沒法做到這麼強大的功能。可以看到,我們一般的使用是 Glide.with(context).load(xxx).into(imageView);
,那就從此處作為入口著手分析。
Glide.with()
首先看Glide的with方法,我這裡是在Activity呼叫的,進去之後是這樣的:
@NonNull public static RequestManager with(@NonNull Activity activity) { return getRetriever(activity).get(activity); }
可以看到這裡,乍一看是獲取一個 RequestManager (RequestManager是請求相關的管理器,後文會提到,這裡先略過),然後可以看到,Glide類中還有很多的過載方法:

getRetriever(Context context)
方法,那我們再進入到getRetriever():
@NonNull private static RequestManagerRetriever getRetriever(@Nullable Context context) { // Context could be null for other reasons (ie the user passes in null), but in practice it will // only occur due to errors with the Fragment lifecycle. Preconditions.checkNotNull( context, "You cannot start a load on a not yet attached View or a Fragment where getActivity() " + "returns null (which usually occurs when getActivity() is called before the Fragment " + "is attached or after the Fragment is destroyed)."); return Glide.get(context).getRequestManagerRetriever(); }
先是判斷了傳進來的context是否為空,然後呼叫了 Glide.get(context).getRequestManagerRetriever()
,先看 Glide.get(context)
:
@NonNull public static Glide get(@NonNull Context context) { if (glide == null) { synchronized (Glide.class) { if (glide == null) { checkAndInitializeGlide(context); } } } return glide; }
這裡採用了設計模式中的單例模式的DCL寫法,以保證整個應用中只有一個Glide例項,方便統一管理和排程。然後再呼叫 getRequestManagerRetriever
:
@NonNull public RequestManagerRetriever getRequestManagerRetriever() { return requestManagerRetriever; }
返回了一個RequestManagerRetriever例項,那麼RequestManagerRetriever是幹嘛的呢?
/** * A collection of static methods for creating new {@link com.bumptech.glide.RequestManager}s or * retrieving existing ones from activities and fragment. */ public class RequestManagerRetriever implements Handler.Callback { //忽略部分程式碼... @NonNull public RequestManager get(@NonNull Context context) { if (context == null) { throw new IllegalArgumentException("You cannot start a load on a null Context"); } else if (Util.isOnMainThread() && !(context instanceof Application)) { if (context instanceof FragmentActivity) { return get((FragmentActivity) context); } else if (context instanceof Activity) { return get((Activity) context); } else if (context instanceof ContextWrapper) { return get(((ContextWrapper) context).getBaseContext()); } } return getApplicationManager(context); } @NonNull public RequestManager get(@NonNull FragmentActivity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); FragmentManager fm = activity.getSupportFragmentManager(); return supportFragmentGet(activity, fm, null /*parentHint*/); } } @NonNull public RequestManager get(@NonNull Fragment fragment) { Preconditions.checkNotNull(fragment.getActivity(), "You cannot start a load on a fragment before it is attached or after it is destroyed"); if (Util.isOnBackgroundThread()) { return get(fragment.getActivity().getApplicationContext()); } else { FragmentManager fm = fragment.getChildFragmentManager(); return supportFragmentGet(fragment.getActivity(), fm, fragment); } } @NonNull public RequestManager get(@NonNull Activity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); android.app.FragmentManager fm = activity.getFragmentManager(); return fragmentGet(activity, fm, null /*parentHint*/); } } @NonNull public RequestManager get(@NonNull View view) { if (Util.isOnBackgroundThread()) { return get(view.getContext().getApplicationContext()); } Activity activity = findActivity(view.getContext()); // The view might be somewhere else, like a service. if (activity == null) { return get(view.getContext().getApplicationContext()); } if (activity instanceof FragmentActivity) { Fragment fragment = findSupportFragment(view, (FragmentActivity) activity); return fragment != null ? get(fragment) : get(activity); } // Standard Fragments. android.app.Fragment fragment = findFragment(view, activity); if (fragment == null) { return get(activity); } return get(fragment); } @NonNull @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public RequestManager get(@NonNull android.app.Fragment fragment) { if (fragment.getActivity() == null) { throw new IllegalArgumentException( "You cannot start a load on a fragment before it is attached"); } if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { return get(fragment.getActivity().getApplicationContext()); } else { android.app.FragmentManager fm = fragment.getChildFragmentManager(); return fragmentGet(fragment.getActivity(), fm, fragment); } } @NonNull private RequestManager getApplicationManager(@NonNull Context context) { // Either an application context or we're on a background thread. if (applicationManager == null) { synchronized (this) { if (applicationManager == null) { Glide glide = Glide.get(context.getApplicationContext()); applicationManager = factory.build( glide, new ApplicationLifecycle(), new EmptyRequestManagerTreeNode(), context.getApplicationContext()); } } } return applicationManager; } @NonNull private RequestManager fragmentGet(@NonNull Context context, @NonNull android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) { RequestManagerFragment current = getRequestManagerFragment(fm, parentHint); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { // TODO(b/27524013): Factor out this Glide.get() call. Glide glide = Glide.get(context); requestManager = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); current.setRequestManager(requestManager); } return requestManager; } @NonNull private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint) { SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { // TODO(b/27524013): Factor out this Glide.get() call. Glide glide = Glide.get(context); requestManager = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); current.setRequestManager(requestManager); } return requestManager; } @NonNull RequestManagerFragment getRequestManagerFragment( @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) { RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); if (current == null) { current = pendingRequestManagerFragments.get(fm); if (current == null) { current = new RequestManagerFragment(); current.setParentFragmentHint(parentHint); pendingRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current; } /** * Used internally to create {@link RequestManager}s. */ public interface RequestManagerFactory { @NonNull RequestManager build( @NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context); } private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() { @NonNull @Override public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) { return new RequestManager(glide, lifecycle, requestManagerTreeNode, context); } }; }
這裡原始碼有點長,先整體貼出來方便觀看整體結構,嫌棄長的話可以先接著看,後面步驟會從程式碼裡截圖分步分析
裡面同樣過載了很多get方法,引數照樣是Activity、Fragment、View、Context等多種型別(先留個疑問,為什麼Glide要這麼做呢?)首先看第一個 get(Context context)
,可以看到裡面對Context的型別做了判斷。

RequestManagerRetriever#get(Context context)
如果是在子執行緒或者Application中呼叫的話,會呼叫 getApplicationManager()
來獲取RequestManager
如果是主執行緒或者普通Context的話均會走各自的get方法,但其實它們本質最後只會呼叫到 fragmentGet
或者 supportFragmentGet

getApplicationManager

其他普通Context獲取的RequestManager

fragmentGet
然後再由它們將當前的Context的傳遞 RequestManagerFactory
的 build
方法,new出了我們需要的RequestManager物件:

RequestManagerFactory
可以看到,兩條線路的主要區別在於傳進去的Lifecycle引數不一樣,Application傳進去的是 ApplicationLifecycle
,而Activity、Fragment等傳進去的是getRequestManagerFragment()獲得的Fragment物件的Lifecycle,那麼 getRequestManagerFragment
獲取的是什麼Fragment呢?,可以看到獲取的是Glide建立的一個隱藏的Fragment—— RequestManagerFragment
。RequestManagerFragment部分原始碼如下:
public class RequestManagerFragment extends Fragment { private final ActivityFragmentLifecycle lifecycle; public RequestManagerFragment() { this(new ActivityFragmentLifecycle()); } @VisibleForTesting @SuppressLint("ValidFragment") RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) { this.lifecycle = lifecycle; } @Override public void onStart() { super.onStart(); lifecycle.onStart(); } @Override public void onStop() { super.onStop(); lifecycle.onStop(); } @Override public void onDestroy() { super.onDestroy(); lifecycle.onDestroy(); unregisterFragmentWithRoot(); } }
不難看出,只要這個Fragment的生命週期一變化,就會呼叫lifecycle的對應函式,那麼ActivityFragmentLifecycle的對應函式又是幹嘛的呢?
class ActivityFragmentLifecycle implements Lifecycle { private final Set<LifecycleListener> lifecycleListeners = Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>()); @Override public void addListener(@NonNull LifecycleListener listener) { lifecycleListeners.add(listener); } @Override public void removeListener(@NonNull LifecycleListener listener) { lifecycleListeners.remove(listener); } void onStart() { for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStart(); } } void onStop() { for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStop(); } } void onDestroy() { for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onDestroy(); } } }
這裡用到了觀察者模式,即一旦它的onStart、onStop等函式被外界呼叫時,就會相應的遍歷呼叫所持有的lifecycleListener物件的生命週期函式,結合上一步,也就是說: Fragment的生命週期一變化,就會呼叫到ActivityFragmentLifecycle類的生命週期函式,進而觸發所有監聽它的lifecycle監聽器 (可還記得剛才提到建立RequestManager的時候是傳進去了我們的ActivityFragmentLifecycle,到時候RequestManager中會呼叫這裡的addListener(this),那麼RequestManager就相當於監聽了ActivityFragmentLifecycle,就相當於我們平時寫監聽事件原理差不多)。
Glide正是利用這個隱藏的Fragment來監聽所在頁面的生命週期,從而控制我們的圖片載入的生命週期(比如頁面銷燬了就停止載入圖片),所以這也就是Glide要過載多個不同型別Context方法的原因,因為Application的Context是隨著整個應用的生命週期變化而變化,Glide只要跟隨著應用生命週期就可以了,但是如果只是具體頁面那肯定有各自單獨的生命週期,因此要區分各個場景來進行初始化。
RequestManagerRetriever分析完畢,其實它就是用來綁定當前生命週期並且返回我們所需要的RequestManager,還記得嗎,剛才我們第一步獲取RequestManager物件的時候,是呼叫的如下程式碼:
@NonNull public static RequestManager with(@NonNull Activity activity) { return getRetriever(activity).get(activity); }
getRetriever剛才也已經說了,是返回一個RequestManagerRetriever例項,那麼這個時候呼叫的正是RequestManagerRetriever的get(Activity activity)方法,也就是說, Glide.with()方法會把我們當前所在的上下文Context傳給Glide的RequestManagerRetriever生成對應的RequestManager物件。 (此處以Activity為例, 會把我們的Activity例項傳到RequestManagerRetriever中並且生成對應的RequestManager)
片尾
至此,Glide.with完成了它的使命。通過它繫結好了生命週期,並且拿到了接下來做請求要涉及到的RequestManager物件。
下集預告(Glide load 初露鋒芒)

關注Android開發小棧,更多原創精選