基于上一篇介紹了Glide的使用篇本文分析一下Glide的源碼實現,看看我們簡單幾步就實現的圖片展示功能在源碼中是怎樣完成的。
一、Glide中的核心文件
先逐個介紹一下個人以為的幾個核心類:?
1、Glide
Glide是必經的入口,通過Glide.get(context)主要是做初始化,包括、Registry、RequestManagerRetriever等核心組件。
2、RequestManagerRetriever
獲取RequestManager,創建無UI的RequestManagerFragment綁定生命周期監聽,通過Lifecycle監聽宿主生命周期。
3、GlideBuilder?
GlideBuilder?它的build方法會配置線程池、緩存策略等、初始化Engine以及初始化Glide對象。
4、RequestBuilder
構建請求參數,asDrawable、asGif、asBitmap加載不同類型,默認asDrawable。最終由Engine調度三級緩存(活動資源/LRU內存/磁盤)。
5、?RequestManager?
管理請求隊列,協調生命周期。
6、RequestManagerFragment
?綁定生命周期?非Application上下文:創建無UI的RequestManagerFragment,通過Lifecycle監聽宿主生命周期。主線程調用時通過FragmentManager管理Fragment,子線程使用Application級生命周期。
7、LifecycleListener
定義生命周期的接口,里面onStart、onStop、onDestroy三個方法與宿主Fragment或Activity的同名生命周期綁定。
8、Engine
合理調度三級緩存(調取活動資源/內存/磁盤)
9、Target?
Target是一個接口,繼承自LifecycleListener并且額外增加了一些加載過程中的方法,比如onLoadStarted、onLoadFailed、onLoadCleared等等。他還有一個抽象的實現類BaseTarget。
后面子子孫孫還有很多抽象類繼承BaseTarget,比如下一代ViewTarget、下下代ImageViewTarget
、下下下代是BitmapImageViewTarget和DrawableImageViewTarget以及ThumbnailImageViewTarget,他們才是into方法傳入的實際展示圖片的控件。
是借助ImageViewTargetFactory來創建對應Target(如BitmapImageViewTarget)。
10、DecodeJob?
看得出來他是做解碼工作的,緩存未命中時創建DecodeJob,提交到EngineJob線程池。實現了Runnable接口因此再run方法中借助DataFetcher進行解碼。
11、DataFetcher
上面提到了借助DataFetcher進行解碼,但他是個接口,所以真正工作是它的實現類們,比如FileFetcher、AssetPathFetcher和HttpUrlFetcher等都不同地址來源的圖片進行解碼。
12、Registry
組件注冊中心,支持擴展ModelLoader等模塊。根據模型類型(如String/File)匹配對應的ModelLoader。
二、分階段梳理工作流程
1、注
Glide.with(mActivity).load(R.drawable.czzs_step_station).into(image);
以在Activity中加載為例,這也是使用最多的場景。其他場景請按此思路自行梳理。
2、初始化階段?:
Glide.with()通過RequestManagerRetriever獲取RequestManager,綁定生命周期監聽。
2.1 獲取RequestManager
public static RequestManager with(Activity activity) {return getRetriever(activity).get(activity);
}
2.2 獲取RequestManagerRetriever
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();
}
順著捋會找到Glide中的initializeGlide方法,此處代碼角度,只貼出實例化GlideBuilder以及通過它的build方法創建Glide對象,并將Glide對象聲明為成員變量。
GlideBuilder builder = new GlideBuilder().setRequestManagerFactory(factory);
for (GlideModule module : manifestModules) {module.applyOptions(applicationContext, builder);
}
if (annotationGeneratedModule != null) {annotationGeneratedModule.applyOptions(applicationContext, builder);
}
Glide glide = builder.build(applicationContext);
for (GlideModule module : manifestModules) {module.registerComponents(applicationContext, glide, glide.registry);
}
if (annotationGeneratedModule != null) {annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
Glide.glide = glide;
然后上面的builder.build(applicationContext);中初始化了Engine、RequestManagerRetriever
以及Glid,當然也創建了線程池,只關鍵部分代碼:
if (engine == null) {engine = new Engine(memoryCache, diskCacheFactory, diskCacheExecutor, sourceExecutor,GlideExecutor.newUnlimitedSourceExecutor());}RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(requestManagerFactory);return new Glide(context,engine,memoryCache,bitmapPool,arrayPool,requestManagerRetriever,connectivityMonitorFactory,logLevel,defaultRequestOptions.lock());
}
2.3 綁定生命周期
現在看2.1中后半部分get(activity),這里是調用RequestManagerRetriever的get方法:
public RequestManager get(Activity activity) {if (Util.isOnBackgroundThread()) {return get(activity.getApplicationContext());} else {assertNotDestroyed(activity);android.app.FragmentManager fm = activity.getFragmentManager();return fragmentGet(activity, fm, null /*parentHint*/);}
}
這里出現了FragmentManager,它就是要創建無UI的RequestManagerFragment,通過Lifecycle監聽宿主生命周期。?創建fragment的代碼:
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm, 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;
}
現在準備工作基本完成了。
2、?加載階段?:
load(R.drawable.czzs_step_station).into(image);
傳入圖片路徑和ImageView組件。
public RequestBuilder<Drawable> load(@Nullable Object model) {return asDrawable().load(model);
}
RequestBuilder構建請求參數,最終由Engine調度三級緩存(活動資源/LRU內存/磁盤)。
public Target<TranscodeType> into(ImageView view) {省略很多行。。。return into(context.buildImageViewTarget(view, transcodeClass));
}
buildImageViewTarget方法創建一個Target實例,其實就是上面提到的BitmapImageViewTarget或DrawableImageViewTarget。
@SuppressWarnings("unchecked")
public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {if (Bitmap.class.equals(clazz)) {return (Target<Z>) new BitmapImageViewTarget(view);} else if (Drawable.class.isAssignableFrom(clazz)) {return (Target<Z>) new DrawableImageViewTarget(view);} else {throw new IllegalArgumentException("Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");}
}
然后進入RequestManager的track方法:
void track(Target<?> target, Request request) {targetTracker.track(target);requestTracker.runRequest(request);
}
下一步
public void runRequest(Request request) {requests.add(request);if (!isPaused) {request.begin();} else {pendingRequests.add(request);}
}
進入Request的實現類SingleRequest中的begin方法開始處理加載。
3、?解碼階段?:
解碼是用DataFetcher和它的子實現類們:
這是加載結果的兩個回調:
這里說一下Glide是怎樣加載網絡圖片的,沒錯,和其他網絡請求一樣她也是用的HttpURLConnection。
在它的實現類HttpUrlFetcher中loadData方法:
@Override
public void loadData(Priority priority, DataCallback<? super InputStream> callback) {long startTime = LogTime.getLogTime();final InputStream result;try {result = loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/,glideUrl.getHeaders());} catch (IOException e) {if (Log.isLoggable(TAG, Log.DEBUG)) {Log.d(TAG, "Failed to load data for url", e);}callback.onLoadFailed(e);return;}if (Log.isLoggable(TAG, Log.VERBOSE)) {Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime)+ " ms and loaded " + result);}callback.onDataReady(result);
}
這里會將結果callback.onDataReady(result);毀掉了上面截圖中提到的onDataReady方法。
調用loadDataWithRedirects方法里:
這里如果失敗還會重新請求連接,最多重連五次:
private static final int MAXIMUM_REDIRECTS = 5;
最后各種通過FetcherReadyCallback以及其他各種回調,最終在BitmapImageViewTarget展示圖片內容:
/*** Sets the {@link android.graphics.Bitmap} on the view using {@link* android.widget.ImageView#setImageBitmap(android.graphics.Bitmap)}.** @param resource The bitmap to display.*/
@Override
protected void setResource(Bitmap resource) {view.setImageBitmap(resource);
}
三、其實還有一些其他很重要的公共類:
有一個線程池:
還一個上下文:
一個異常類:
Glide是一個非常優秀的框架,源碼架構設計的太好了。另外想了解Glide使用的朋友可以參考上一篇《展開說說Android之Glide詳解_使用篇》。
個人總結記錄,才疏學淺,如有錯誤,歡迎指正,多謝。?