文章篇幅較多.建議配合源碼閱讀并且有空閑時間去理解
Glide基本使用
RequestOptions options = new RequestOptions()
.placeholder(R.mipmap.ic_launcher) //占位圖
.error(R.mipmap.ic_launcher)//加載失敗圖
.circleCrop();//圓形
Glide.with(this) //初始化Glide Glide的生命周期
.load(beans.get(0).getData().get(position).getImagePath())//圖片地址
.apply(options) //添加請求的參數(shù)
.centerCrop()//圖片加載樣式
.into(imageView);//加載的View
基本概念
- Model 類型
- Data 輸入流
- Resource 解碼后資源
- TransformedResource 轉(zhuǎn)換后的資源
- TranscodedResource 轉(zhuǎn)碼完成后的資源
- Target 顯示目標
with方法
傳入的context對象表示當(dāng)前Glide的加載生命周期,如果傳入Activity時調(diào)用onDestroy方法當(dāng)前Glide加載的圖片就會銷毀
- 得到一個
RequestManager主要用來控制整個界面的生命周期 -
RequestManagerRetriever是用來生產(chǎn)RequestManager的 -
RequestManagerFragment無界面的Fragment用來綁定生命周期
public static RequestManager with(@NonNull Context context) {
//返回一個RequestManagerRetriever象
// 獲取一個 RequestManagerRetriever 描述一個圖片加載請求的管理者
return getRetriever(context).get(context);
}
//
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
//...檢查Glide是否初始化
//得到一個glide對象 通過glide得到一個RequestManager 在glide構(gòu)造方法中
return Glide.get(context).getRequestManagerRetriever();
}
RequestManagerRetriever
得到一個requestManagerRetriever對象,并且這里還需要返回一個Glide實例
public class Glide implements ComponentCallbacks2 {
private static volatile Glide glide;
private static volatile boolean isInitializing; //是否初始化
//單例得到Glide
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
private static void checkAndInitializeGlide(@NonNull Context context) {
if (isInitializing) {
//如果已經(jīng)初始化 拋出異常
}
isInitializing = true;
initializeGlide(context); //初始化Glide
isInitializing = false;
}
private static void initializeGlide(@NonNull Context context) {
//GlideBuilder來初始化Glide
initializeGlide(context, new GlideBuilder());
}
//初始化Glide
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext(); //得到當(dāng)前的Application
//獲取 @GlideModule 注解驅(qū)動生成的 GeneratedAppGlideModuleImpl和GeneratedAppGlideModuleFactory 類
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
//返回一個空的collections的集合
List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
//判斷@GlideModule的類是否為空或者是在Manifest中去注解isManifestParsingEnabled默認情況下返回True
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
//通過Manifest中去得到GlideModule模塊
manifestModules = new ManifestParser(applicationContext).parse();
}
//當(dāng)返回的GlideModule注解不為空并且注解生成的類模塊不為空
if (annotationGeneratedModule != null
&& !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
//得到當(dāng)前的GlideModule注解模塊
Set<Class<?>> excludedModuleClasses =
annotationGeneratedModule.getExcludedModuleClasses();
//通過iterator來循環(huán)
Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
while (iterator.hasNext()) {
//得到當(dāng)前的注解模塊
com.bumptech.glide.module.GlideModule current = iterator.next();
//如果已經(jīng)排除的模塊不包含當(dāng)前的類,結(jié)束本次循環(huán)
if (!excludedModuleClasses.contains(current.getClass())) {
continue;
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
}
//如果包含當(dāng)前類 則移除這個類
iterator.remove();
}
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
}
}
//嘗試從注解生成的 annotationGeneratedModule 中獲取 RequestManager 的構(gòu)造工廠對象
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory() : null;
//設(shè)置當(dāng)前的請求管理工廠
builder.setRequestManagerFactory(factory);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.applyOptions(applicationContext, builder);
}
//構(gòu)建Glide實體對象
Glide glide = builder.build(applicationContext);
//循環(huán)mainFast注解注冊的模塊 Glide3 版本通用的注冊模式 V4版本不再使用
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
try {
//嘗試去注冊Glide ||得到注冊的生命周期, Glide對象 ,注冊管理器,包含注冊編碼,解碼和編碼的邏輯
module.registerComponents(applicationContext, glide, glide.registry);
} catch (AbstractMethodError e) {
throw new IllegalStateException(
"Attempting to register a Glide v3 module. If you see this, you or one of your"
+ " dependencies may be including Glide v3 even though you're using Glide v4."
+ " You'll need to find and remove (or update) the offending dependency."
+ " The v3 module name is: " + module.getClass().getName(), e);
}
}
//如果當(dāng)前annotationGeneratedModule 注解的模塊不為空
if (annotationGeneratedModule != null) {
//注冊Glide組件
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
//把Glide綁定到glide傳進來的生命周期中 用于檢測系統(tǒng) Config 改變和內(nèi)存占用量低的信號
applicationContext.registerComponentCallbacks(glide);
//存在靜態(tài)的成員變量中
Glide.glide = glide;
}
}
Glide的構(gòu)建過程
public final class GlideBuilder {
private final Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions = new ArrayMap<>();
//管理線程池的引擎
private Engine engine;
//享元復(fù)用池
private BitmapPool bitmapPool;
private ArrayPool arrayPool;
//線程池
private GlideExecutor sourceExecutor;
private GlideExecutor diskCacheExecutor;
private GlideExecutor animationExecutor;
//磁盤緩存
private DiskCache.Factory diskCacheFactory;
//內(nèi)存緩存
private MemorySizeCalculator memorySizeCalculator;
private MemoryCache memoryCache;
//連接監(jiān)視器
private ConnectivityMonitorFactory connectivityMonitorFactory;
//請求構(gòu)造器
private RequestOptions defaultRequestOptions = new RequestOptions();
//請求構(gòu)建工廠
@Nullable
private RequestManagerFactory requestManagerFactory;
//是否保留Activity中的資源
private boolean isActiveResourceRetentionAllowed;
//請求監(jiān)聽器
@Nullable
private List<RequestListener<Object>> defaultRequestListeners;
@NonNull
Glide build(@NonNull Context context) {
if (sourceExecutor == null) {
//網(wǎng)絡(luò)使用連接池
sourceExecutor = GlideExecutor.newSourceExecutor();
}
if (diskCacheExecutor == null) {
//磁盤緩存連接池
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
if (animationExecutor == null) {
//執(zhí)行動畫池
animationExecutor = GlideExecutor.newAnimationExecutor();
}
if (memorySizeCalculator == null) {
//描述一個內(nèi)存的計算器, 智能加載圖片的大小, 判斷其需要的內(nèi)存空間
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
if (connectivityMonitorFactory == null) {
//默認的連接監(jiān)聽工廠
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
//bitMap的復(fù)用池
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
//數(shù)組復(fù)用池
if (arrayPool == null) {
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
//資源緩存池
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
//次盤緩存工廠
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
//構(gòu)建了一個負責(zé)管理線程池與緩存的執(zhí)行引擎
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
animationExecutor,
isActiveResourceRetentionAllowed);
}
//默認請求監(jiān)聽器
if (defaultRequestListeners == null) {
defaultRequestListeners = Collections.emptyList();
} else {
defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
}
//一個 RequestManagerRetriever 對象
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
//構(gòu)建一個Glide對象
return new Glide(
context, //上下文環(huán)境
engine,//執(zhí)行引擎
memoryCache,//內(nèi)存緩存
bitmapPool,//bitMap的復(fù)用池
arrayPool,//數(shù)組復(fù)用池
requestManagerRetriever,//請求管理類
connectivityMonitorFactory,//連接監(jiān)聽器
logLevel,//log等級
defaultRequestOptions.lock(),//默認請求選項
defaultTransitionOptions,//默認的轉(zhuǎn)換選項
defaultRequestListeners,//默認的請求監(jiān)聽
isLoggingRequestOriginsEnabled);//是否開啟請求資源的日志
}
}
Glide 對象的構(gòu)建過程異常的復(fù)雜, 筆者調(diào)整了部分的數(shù)據(jù), 它們的流程如下
- 構(gòu)建線程池 ------>根據(jù)不同的任務(wù)構(gòu)建不同的線程池
- 構(gòu)建內(nèi)存緩存策略 ----> 1.內(nèi)存計算器 2. Lru緩存算法
- 構(gòu)建對象復(fù)用池
- 構(gòu)建工廠類 -->創(chuàng)了一個
RequestManagerRetriever對象的工廠 - 構(gòu)建 Glide 執(zhí)行引擎 ----->用于管理線程池和緩存
- 創(chuàng)建 Glide 對象
- 將
Glide Builder中的數(shù)據(jù)導(dǎo)入 - 構(gòu)建一個
registry, 注冊了眾多的編解碼器 - 構(gòu)建了一個
Glide Context對象, 描述其數(shù)據(jù)資源的上下文
- 將
從 Glide 構(gòu)造的流程中, 可以看到它主要有五個核心部分, 線程池, 內(nèi)存緩存策略, 對象復(fù)用策略和圖片 ,音視頻的編解碼
??在創(chuàng)建GlideBuilder.build中, 我們看到了它 new 了一個RequestManagerRetriever 對象并且傳遞到了 Glide 對象內(nèi)部, 于是通過 Glide.getRequestManagerRetriever就可以很方便的獲取到 RequestManagerRetriever這個對象了
??獲取到了 RequestManagerRetriever 實例后, 接下來就可以通過 RequestManagerRetriever.get() 方法獲取 RequestManager 對象了
得到RequestManager
public class RequestManagerRetriever implements Handler.Callback {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
//下面是判斷當(dāng)前的Context的載體
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());
}
}
//若不在 MainThread 或 context 為 Application 的類型, 則使用 ApplicationManager
return getApplicationManager(context);
}
-
RequestManagerRetriever.get方法會判斷 Context 的類型- 若在主線程并且不為
Application類型的 Context 則找尋其依賴的 Activity - 若非主線程或為
Application類型的 Context, 則使用ApplicationManage
- 若在主線程并且不為
獲取Activity的RequestManager
public RequestManager get(@NonNull Activity activity) {
//判斷是否在子線程
if (Util.isOnBackgroundThread()) {
//子線程返回Application對象的RequestManager
return get(activity.getApplicationContext());
} else {
//主線程
assertNotDestroyed(activity); //不能在銷毀Activity時候去加載
android.app.FragmentManager fm = activity.getFragmentManager();//獲取其 FragmentManager
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
//1. 從 Activity 中獲取一個 RequestManagerFragment, 用于監(jiān)管 Activity 的聲明周期
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
// 2. 獲取 Fragment 中保存的當(dāng)前頁面的請求管理器
RequestManager requestManager = current.getRequestManager();
// 3. 不存在則創(chuàng)建一個請求管理器保存在 RequestManagerFragment 中
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;
}
// 描述一個即將被 FragmentManager 添加的 RequestManagerFragment 緩存
final Map<android.app.FragmentManager, RequestManagerFragment> pendingRequestManagerFragments =
new HashMap<>();
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
//1 嘗試從 FragmentManager 中獲取這個 Fragment
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
//2 不存在則添加一個
if (current == null) {
//3 從 pendingRequestManagerFragments 緩存中獲取一個
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
//3.1 創(chuàng)建并更新到緩存
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
//執(zhí)行Glide生命周期的start
current.getGlideLifecycle().onStart();
}
//3.2 添加到等待被添加的緩存中因為添加到 FragmentManager 有延遲, 用這種方式防止同一時間創(chuàng)建了兩個 RequestManagerFragment 對象添加到 Activity 中
pendingRequestManagerFragments.put(fm, current);
//3.3 添加到 FragmentManager 中
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
//3.4 添加到 FragmentManager 成功, 通過 Handler 移除這個緩存
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
??可以看到 RequestManagerRetriever 的 get方法主要是在 Activity頁面中添加一個RequestManagerFragment 實例, 以便用于監(jiān)聽Activity的生命周期, 然后給這個 Fragment 注入一個RequestManager, 其處理的細節(jié)代碼中也注釋的比較詳細
- 其中有個非常引人注目的細節(jié), 考慮到將
FragmentManger添加Fragment有延遲, 為了防止同一時間創(chuàng)建了兩個RequestManagerFragment添加到FragmentManager, 因此它使用了pendingRequestManagerFragments進行緩存
獲取 Application 的RequestManager
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) {
//構(gòu)建Glide對象
Glide glide = Glide.get(context.getApplicationContext());
//得到RequestManager對象
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
關(guān)于with方法總結(jié)
至此 with方法全部結(jié)束簡單總結(jié)一下
- 構(gòu)建
Glide實例 - 獲取
RequestManagerRetriever對象 - 構(gòu)建
RequestManager對象- 若可以綁定
Activity, 則為Activity添加一個RequestManagerFragment, 其內(nèi)部含有ReqeustManager對象, 以便后續(xù)直接根據(jù)Activity的生命周期管控Glide請求的處理 - 若非可綁定
Activity, 則獲取一個單例的applicationManager專門用于處理這類請求
- 若可以綁定
Load方法(RequestManager)
public class RequestManager implements LifecycleListener,
ModelTypes<RequestBuilder<Drawable>> {
//load
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
// 構(gòu)建一個 RequestBuilder,描述一個目標資源為 Drawable 的圖片加載請求
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
}
- load方法()
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
implements Cloneable,
ModelTypes<RequestBuilder<TranscodeType>> {
private Object model;//描述已經(jīng)加載的資源
// 描述這個請求是否已經(jīng)添加了加載的數(shù)據(jù)源
private boolean isModelSet;
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
}
Into方法(RequestBuilder)
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread(); //檢測是否是主線程
Preconditions.checkNotNull(view); //檢測View是否為空
//根據(jù) view 的 scaleType 重構(gòu) RequestOptions RequestBuilder 直接繼承了 BaseRequestOptions
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
// 1.1 克隆原 RequestOptions, 配置一個 CenterCrop 的縮放選項
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
// 2. 調(diào)用 into 方法, 創(chuàng)建并且執(zhí)行請求
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
可以看到 into 方法中
- 第一步是根據(jù)
ImageView的ScaleType來配置Options選項 - 第二步調(diào)用了重載方法
into執(zhí)行后續(xù)構(gòu)建請求操作
配置 Options
public abstract class BaseRequestOptions<T extends BaseRequestOptions<T>> implements Cloneable {
...
public T optionalCenterCrop() {
//optionalTransform DownsampleStrategy 描述降采樣壓縮的策略 CenterCrop 描述圖像變化方式
return optionalTransform(DownsampleStrategy.CENTER_OUTSIDE, new CenterCrop());
}
final T optionalTransform(@NonNull DownsampleStrategy downsampleStrategy,
@NonNull Transformation<Bitmap> transformation) {
if (isAutoCloneEnabled) {
return clone().optionalTransform(downsampleStrategy, transformation);
}
//2. 將降采樣壓縮策略添加到 options 中
downsample(downsampleStrategy);
// 3. 將圖像變化方式添加到 transformations 中
return transform(transformation, /*isRequired=*/ false);
}
//壓縮策略
public T downsample(@NonNull DownsampleStrategy strategy) {
//調(diào)用了 set, 將降采樣策略保存到 options 中
return set(DownsampleStrategy.OPTION, Preconditions.checkNotNull(strategy));
}
public <Y> T set(@NonNull Option<Y> option, @NonNull Y value) {
if (isAutoCloneEnabled) {
return clone().set(option, value);
}
Preconditions.checkNotNull(option);
Preconditions.checkNotNull(value);
// 2.2 添加到 options 緩存中
options.set(option, value);
return selfOrThrowIfLocked();
}
T transform(
@NonNull Transformation<Bitmap> transformation, boolean isRequired) {
if (isAutoCloneEnabled) {
return clone().transform(transformation, isRequired);
}
// 3.1 調(diào)用了 transform 的重載方法, 將這個圖像變化的方式作用到多種資源類型上
DrawableTransformation drawableTransformation =
new DrawableTransformation(transformation, isRequired);
transform(Bitmap.class, transformation, isRequired);//Bitmap類型資源
transform(Drawable.class, drawableTransformation, isRequired);//Drawable類型資源
transform(BitmapDrawable.class, drawableTransformation.asBitmapDrawable(), isRequired);//BitmapDrawable類型資源
transform(GifDrawable.class, new GifDrawableTransformation(transformation), isRequired);//動圖資源
return selfOrThrowIfLocked();
}
private Map<Class<?>, Transformation<?>> transformations = new CachedHashCodeArrayMap<>();
<Y> T transform(@NonNull Class<Y> resourceClass, @NonNull Transformation<Y> transformation,
boolean isRequired) {
if (isAutoCloneEnabled) {
return clone().transform(resourceClass, transformation, isRequired);
}
Preconditions.checkNotNull(resourceClass);//空檢測
Preconditions.checkNotNull(transformation);//空檢測
// 3.2 添加到了 transformations 緩存中
transformations.put(resourceClass, transformation);
fields |= TRANSFORMATION;
isTransformationAllowed = true;
fields |= TRANSFORMATION_ALLOWED;
isScaleOnlyOrNoTransform = false;
if (isRequired) {
fields |= TRANSFORMATION_REQUIRED;
isTransformationRequired = true;
}
return selfOrThrowIfLocked();
}
}
可以看到配置縮放選項的操作除了添加了圖像變化操作, 還設(shè)定了采樣方式, 分別保存在 transformations 和 options 中
構(gòu)建 Request請求
return into(glideContext.buildImageViewTarget(view, transcodeClass),
// 2.1 調(diào)用 GlideContext.buildImageViewTarget 構(gòu)建一個 ViewTarget
requestOptions,
Executors.mainThreadExecutor());
我們知道 GlideContext是在 Glide 對象構(gòu)造時一并創(chuàng)建的, 它是 Context的裝飾者對象, 在 Application類型的 Context 中, 添加了 Glide 相關(guān)的數(shù)據(jù), 我們先看看它是如何構(gòu)建 ViewTarget
public class GlideContext extends ContextWrapper {
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
// 調(diào)用工廠類來創(chuàng)建一個 imageView 的 ViewTarget
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
}
public class ImageViewTargetFactory {
@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
@NonNull Class<Z> clazz) {
// 根據(jù)目標編碼的類型來創(chuàng)建不同的 ViewTarget 對象, 因為我們沒有 asBitmap, 因此這里為 Drawable
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
}
可以看到 GlideContext中通過工廠類創(chuàng)建了ImageView 的 ViewTarget 的, 它描述的是圖像處理結(jié)束之后, 最終要作用到的 View 目標
構(gòu)建好了ViewTarge, 接下來就可以分析重載的into方法了, 看看它是如何構(gòu)建請求的
private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener,BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
// 調(diào)用 buildRequest 構(gòu)建了一個 request 請求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
// 處理這個 ViewTarget 之前的請求與新請求的沖突
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request);
// 調(diào)用了請求 RequestManager.track 方法執(zhí)行請求
requestManager.track(target, request);
return target;
}
可以看到調(diào)用了buildRequest構(gòu)建了一個 Glide 的請求, 其構(gòu)建過程也非常有意思, 最終最調(diào)用SingleRequest.obtain構(gòu)建一個Request 的實例對象, 之后便是調(diào)用 RequestManager.track將其分發(fā)并執(zhí)行了
Into的總結(jié)
- 根據(jù)
ImageView構(gòu)建采樣壓縮和圖像變化的策略保存在Options和Transform中 - 構(gòu)建
ViewTarget描述這個請求要作用的View對象 - 構(gòu)建
Request請求并執(zhí)行
圖1.png
獲取數(shù)據(jù)源
在上面的into方法中我們已經(jīng)成功構(gòu)建一個Request 這里我們繼續(xù)往下看
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);//跟蹤生命周期
requestTracker.runRequest(request);//開始請求數(shù)據(jù)
}
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
//開始執(zhí)行請求
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
public final class SingleRequest<R> implements Request,
SizeReadyCallback,
ResourceCallback,
FactoryPools.Poolable {
public synchronized void begin() {
....
//完成狀態(tài)
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
//等待狀態(tài)
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
//表示尺寸準備好了
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
....
}
public synchronized void onSizeReady(int width, int height) {
...
//通過引擎的load方法構(gòu)造請求
loadStatus =
engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this,
callbackExecutor);
....
}
}
任務(wù)的構(gòu)建(load)
public synchronized <R> LoadStatus load( ...) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
//根據(jù)傳入的參數(shù), 構(gòu)建這個請求的 key
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
// 2. 嘗試從 ActiveResources 緩存中查找這個 key 的緩存
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
// 若緩存存在, 則直接回調(diào) onResourceReady 處理后續(xù)操作
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
//嘗試從 LruResourceCache 中找尋這個資源
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
// 回調(diào) onResourceReady 處理后續(xù)操作
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
//從緩存中查找 key 對應(yīng)的任務(wù)
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
//走到這里說明這個任務(wù)已經(jīng)正在執(zhí)行了, 無需再次構(gòu)建執(zhí)行
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
//返回加載狀態(tài)即可
return new LoadStatus(cb, current);
}
//構(gòu)建一個新的引擎任務(wù)
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
//構(gòu)建解碼任務(wù)
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
//添加到任務(wù)緩存
jobs.put(key, engineJob);
//添加回調(diào)監(jiān)聽器
engineJob.addCallback(cb, callbackExecutor);
//執(zhí)行任務(wù)
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
Load方法的作用是:
構(gòu)建這個請求的
key從緩存中查找
key對應(yīng)的資源, 若存在直接回onResourceReady表示資源準備好了從緩存中查找
key對應(yīng)的任務(wù)若存在則說明無需再次獲取資源
-
不存在需要構(gòu)建新的任務(wù)
- 構(gòu)建引擎任務(wù)
EngineJob - 引擎的任務(wù)為解碼任務(wù)
DecodeJob - 將任務(wù)添加到緩存, 防止多次構(gòu)建
- 執(zhí)行任務(wù)
- 構(gòu)建引擎任務(wù)
任務(wù)執(zhí)行(start)
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor(); //獲取線程池
executor.execute(decodeJob); //執(zhí)行線程池
}
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
Runnable,
Comparable<DecodeJob<?>>,
Poolable {
public void run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
//調(diào)用runWrapped
runWrapped();
} catch (CallbackException e) {
...
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//獲取任務(wù)的場景
stage = getNextStage(Stage.INITIALIZE);
//獲取這個場景的執(zhí)行者
currentGenerator = getNextGenerator();
// 執(zhí)行者執(zhí)行任務(wù)
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
//獲取任務(wù)的場景
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
//若我們配置的緩存策略允許從 資源緩存 中讀數(shù)據(jù), 則返回 Stage.RESOURCE_CACHE
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
//若我們配置的緩存策略允許從 源數(shù)據(jù)緩存中讀數(shù)據(jù), 則返回 Stage.DATA_CACHE
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// 若只能允許從緩存中獲取數(shù)據(jù), 則直接 FINISH, 否則返回 Stage.SOURCE, 意為加載一個新的資源
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
//獲取這個場景的執(zhí)行者
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
//資源磁盤緩存的執(zhí)行者
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
//源數(shù)據(jù)磁盤緩存的執(zhí)行者
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
//無緩存, 獲取數(shù)據(jù)的源的執(zhí)行者
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
//執(zhí)行者執(zhí)行任務(wù)
private void runGenerators() {
currentThread = Thread.currentThread();//得到當(dāng)前線程
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//currentGenerator.startNext()執(zhí)行請求操作
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);//得到下一個任務(wù)
currentGenerator = getNextGenerator();//得到下一個任務(wù)的執(zhí)行者
if (stage == Stage.SOURCE) {
//重新調(diào)度任務(wù)
reschedule();
return;
}
}
}
}
DecodeJob 任務(wù)執(zhí)行時, 它根據(jù)不同的場景, 獲取不同的場景執(zhí)行器, 然后調(diào)用了它們的 startNext 方法加載請求任務(wù)的數(shù)據(jù), 其映射表為
| 場景 | 場景描述 | 場景執(zhí)行器 |
|---|---|---|
| Stage.RESOURCE_CACHE | 從磁盤中緩存的資源中獲取數(shù)據(jù) | ResourceCacheGenerator |
| Stage.DATA_CACHE | 從磁盤中緩存的源數(shù)據(jù)中獲取數(shù)據(jù) | DataCacheGenerator |
| Stage.SOURCE | 重新請求數(shù)據(jù) | SourceGenerator |
我們知道在 Engine 中, 嘗試從內(nèi)存緩存中獲取資源, 而 DecodeJob 則是嘗試從磁盤緩存中獲取資源, 我們這里主要查看 SourceGenerator.startNext 是如何加載請求任務(wù)的數(shù)據(jù)的
獲取源數(shù)據(jù)(startNext)
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
// 1. 從 DecodeHelper 的數(shù)據(jù)加載集合中, 獲取一個數(shù)據(jù)加載器
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//2. 使用加載器中 fetcher 執(zhí)行數(shù)據(jù)加載
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
SourceGenerator 主要有兩步
- 調(diào)用
DecodeHelper.getLoadData獲取當(dāng)前請求的數(shù)據(jù)加載器 - 調(diào)用加載器中的
fetcher.loadData真正的執(zhí)行數(shù)據(jù)加載
獲取數(shù)據(jù)加載器
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
// 1. 從 Glide 注冊的 register 中獲取請求 model 加載器
List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
// 遍歷每一個 modelLoaders
for (int i = 0, size = modelLoaders.size(); i < size; i++) {
// 2. 通過 modelLoaders 構(gòu)建 loadData
ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
LoadData<?> current =
modelLoader.buildLoadData(model, width, height, options);
if (current != null) {
// 添加到緩存
loadData.add(current);
}
}
}
return loadData;
}
- 它會找到一個
ModelLoader的實現(xiàn)類, 通過這個實現(xiàn)類的handles方法, 判斷是否可以加載這個model - 這里我們的
model以網(wǎng)絡(luò)的 URL 資源舉例, 它的實現(xiàn)類為HttpGlideUrlLoader我們看看它如何構(gòu)建一個LoadData對象的
- HttpGlideUrlLoader.java
public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
@NonNull Options options) {.
GlideUrl url = model;
if (modelCache != null) {
url = modelCache.get(model, 0, 0);
if (url == null) {
modelCache.put(model, 0, 0, model);
url = model;
}
}
int timeout = options.get(TIMEOUT);
// 創(chuàng)建了一個 LoadData 對象, 并且實例化了一個 HttpUrlFetcher 給它
return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
好的, 可以看到對于 URL 的加載, 其 fetcher 為一個 HttpUrlFetcher的實例, 接下來我們看看數(shù)據(jù)加載的流程
執(zhí)行數(shù)據(jù)加載
- HttpUrlFetcher.java
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
// 獲取網(wǎng)絡(luò)圖片, 內(nèi)部使用了 HttpConnection 實現(xiàn), 僅僅做了重定向的處理
//loadDataWithRedirects 內(nèi)部采用HttpConnection 實現(xiàn)
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
// 將 inputStream 回調(diào)出去
callback.onDataReady(result);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
}
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
}
}
}
數(shù)據(jù)加載的過程也是很簡單的, HttpUrlFetcher 它使用了 HttpConnection 發(fā)起了網(wǎng)絡(luò)請求, 獲取了數(shù)據(jù)流, 至此數(shù)據(jù)資源的獲取就已經(jīng)完成了, 后面要做的便是最重要的數(shù)據(jù)處理了, 它通過回調(diào)的方式將 InputStream扔了出去, 最終會回溯到 DecodeJob 的 onDataFetcherReady 這個方法中
總結(jié)
走到這里, 一個請求的數(shù)據(jù)源獲取就已經(jīng)完成, 還剩下對數(shù)據(jù)源的處理操作, 一次 Glide 數(shù)據(jù)加載就完成了, 我們先回顧一下這次加載的流程圖
優(yōu)先從 memoryCache 中獲取 (內(nèi)存)
ActiveResourceLruResourceCache
次優(yōu)先從diskCache 中獲取 (磁盤)
-
Resource資源緩存 -
Data源數(shù)據(jù)緩存
執(zhí)行新的加載任務(wù)獲取源數(shù)據(jù) (網(wǎng)絡(luò)請求)
- 通過
SourceGenerator獲取數(shù)據(jù) - 通過
HttpUrlFetcher獲取網(wǎng)絡(luò)數(shù)據(jù)流

數(shù)據(jù)源的處理
DecodeJob.java
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;//保存數(shù)據(jù)的 key
this.currentData = data;//保存數(shù)據(jù)的實體
this.currentFetcher = fetcher;//保存數(shù)據(jù)的獲取器
this.currentDataSource = dataSource;//數(shù)據(jù)來源: url 為 REMOTE 類型的枚舉, 表示從遠程獲取
this.currentAttemptingKey = attemptedKey;//嘗試解碼的key
if (Thread.currentThread() != currentThread) { //不是主線程
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);//線程調(diào)度
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");//開啟跟蹤
try {
//嘗試解析數(shù)據(jù)
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();//結(jié)束
}
}
}
private void decodeFromRetrievedData() {
...
Resource<R> resource = null;
try {
//解析數(shù)據(jù)
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
//解析成功,通知外界資源解析成功
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
資源的獲取
private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data,
DataSource dataSource) throws GlideException {
try {
if (data == null) {
return null;
}
long startTime = LogTime.getLogTime();
//解析數(shù)據(jù)
Resource<R> result = decodeFromFetcher(data, dataSource);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded result " + result, startTime);
}
return result;
} finally {
fetcher.cleanup();
}
}
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
throws GlideException {
// 獲取當(dāng)前數(shù)據(jù)類的解析器 LoadPath
LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
// 通過解析器來解析來解析數(shù)據(jù)
return runLoadPath(data, dataSource, path);
}
private <Data, ResourceType> Resource<R> runLoadPath(Data data, DataSource dataSource,
LoadPath<Data, ResourceType, R> path) throws GlideException {
Options options = getOptionsWithHardwareConfig(dataSource);
//根據(jù)數(shù)據(jù)類型獲取一個數(shù)據(jù)重造器, 獲取的數(shù)據(jù)為 InputStream, 因此它是一個 InputStreamRewinder 的實例
DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
try {
// 將解析資源的任務(wù)轉(zhuǎn)移到了 LoadPath.load 方法中
return path.load(
rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
} finally {
rewinder.cleanup();
}
}
可以看到為了解析數(shù)據(jù), 首先構(gòu)建了一個 LoadPath, 然后創(chuàng)建了一個 InputStreamRewinder 類型的 DataRewinder, 最終將數(shù)據(jù)解析的操作到了 LoadPath.load 方法中
public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int width,
int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException {
List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
try {
return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
} finally {
listPool.release(throwables);
}
}
private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder,
@NonNull Options options,
int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback,
List<Throwable> exceptions) throws GlideException {
Resource<Transcode> result = null;
//遍歷內(nèi)部存儲的 DecodePath 集合, 通過他們來解析數(shù)據(jù)
for (int i = 0, size = decodePaths.size(); i < size; i++) {
DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
try {
//調(diào)用 DecodePath.decode 真正進行數(shù)據(jù)的解析
result = path.decode(rewinder, width, height, options, decodeCallback);
} catch (GlideException e) {
exceptions.add(e);
}
if (result != null) {
break;
}
}
if (result == null) {
throw new GlideException(failureMessage, new ArrayList<>(exceptions));
}
return result;
}
public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
@NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
//1. 調(diào)用 decodeResource 將源數(shù)據(jù)解析成中間資源
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
//2. 調(diào)用 DecodeCallback.onResourceDecoded 處理中間資源
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
//3. 調(diào)用 ResourceTranscoder.transcode 將中間資源轉(zhuǎn)為目標資源
return transcoder.transcode(transformed, options);
}
private Resource<ResourceType> decodeResource(DataRewinder<DataType> rewinder, int width,
int height, @NonNull Options options) throws GlideException {
List<Throwable> exceptions = Preconditions.checkNotNull(listPool.acquire());
try {
//調(diào)用了 decodeResourceWithList
return decodeResourceWithList(rewinder, width, height, options, exceptions);
} finally {
listPool.release(exceptions);
}
}
private Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder, int width,
int height, @NonNull Options options, List<Throwable> exceptions) throws GlideException {
Resource<ResourceType> result = null;
for (int i = 0, size = decoders.size(); i < size; i++) {
ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
try {
DataType data = rewinder.rewindAndGet();
if (decoder.handles(data, options)) {
data = rewinder.rewindAndGet();
// 調(diào)用 ResourceDecoder.decode 解析源數(shù)據(jù)
result = decoder.decode(data, width, height, options);
}
} catch (IOException | RuntimeException | OutOfMemoryError e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Failed to decode data for " + decoder, e);
}
exceptions.add(e);
}
if (result != null) {
break;
}
}
if (result == null) {
throw new GlideException(failureMessage, new ArrayList<>(exceptions));
}
return result;
}
可以看到數(shù)據(jù)解析的任務(wù)最重是通過 DecodePath來執(zhí)行的, 它內(nèi)部有三個操作
- 調(diào)用
decodeResource將源數(shù)據(jù)解析成資源- 源數(shù)據(jù):
InputStream - 中間產(chǎn)物:
Bitmap
- 源數(shù)據(jù):
- 調(diào)用
DecodeCallback.onResourceDecoded處理資源 - 調(diào)用
ResourceTranscoder.transcode將資源轉(zhuǎn)為目標資源- 目標資源類型:
Drawable
- 目標資源類型:
1. 解析源數(shù)據(jù)
StreamBitmapDecoder.java
public Resource<Bitmap> decode(@NonNull InputStream source, int width, int height,
@NonNull Options options)
throws IOException {
final RecyclableBufferedInputStream bufferedStream;
final boolean ownsBufferedStream;
...
ExceptionCatchingInputStream exceptionStream =
ExceptionCatchingInputStream.obtain(bufferedStream);
MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream);
UntrustedCallbacks callbacks = new UntrustedCallbacks(bufferedStream, exceptionStream);
try {
// 根據(jù)請求配置的數(shù)據(jù), 對數(shù)據(jù)流進行采樣壓縮, 獲取到一個 Resource<Bitmap>
return downsampler.decode(invalidatingStream, width, height, options, callbacks);
} finally {
exceptionStream.release();
if (ownsBufferedStream) {
bufferedStream.release();
}
}
}
Downsampler.java
public Resource<Bitmap> decode(InputStream is, int requestedWidth, int requestedHeight,
Options options, DecodeCallbacks callbacks) throws IOException {
Preconditions.checkArgument(is.markSupported(), "You must provide an InputStream that supports"
+ " mark()");
byte[] bytesForOptions = byteArrayPool.get(ArrayPool.STANDARD_BUFFER_SIZE_BYTES, byte[].class);
BitmapFactory.Options bitmapFactoryOptions = getDefaultOptions();
bitmapFactoryOptions.inTempStorage = bytesForOptions;
DecodeFormat decodeFormat = options.get(DECODE_FORMAT);
DownsampleStrategy downsampleStrategy = options.get(DownsampleStrategy.OPTION);
boolean fixBitmapToRequestedDimensions = options.get(FIX_BITMAP_SIZE_TO_REQUESTED_DIMENSIONS);
boolean isHardwareConfigAllowed =
options.get(ALLOW_HARDWARE_CONFIG) != null && options.get(ALLOW_HARDWARE_CONFIG);
try {
Bitmap result = decodeFromWrappedStreams(is, bitmapFactoryOptions,
downsampleStrategy, decodeFormat, isHardwareConfigAllowed, requestedWidth,
requestedHeight, fixBitmapToRequestedDimensions, callbacks);
//用線程池把流轉(zhuǎn)為Resource<Bitmap>
return BitmapResource.obtain(result, bitmapPool);
} finally {
releaseOptions(bitmapFactoryOptions);
byteArrayPool.put(bytesForOptions);
}
}
可以看到它內(nèi)部通過Downsampler.decode方法對數(shù)據(jù)流進行采樣壓縮, 來獲取這個流的Bitmap
- 這個采樣的策略就是我們在構(gòu)建
Request時傳入的, 其采樣壓縮的細節(jié), 并不是我們本次關(guān)注的重點
我們看看獲取到了 Resource 之后, 如何處理這個資源
2. 資源的處理
可以看到, 當(dāng)我們將源數(shù)據(jù)解析成對應(yīng)的資源之后, 便會調(diào)用 DecodeCallback.onResourceDecoded 處理資源, 我們看看它
的處理過程
@Override
public Resource<Z> onResourceDecoded(@NonNull Resource<Z> decoded) {
return DecodeJob.this.onResourceDecoded(dataSource, decoded);
}
<Z> Resource<Z> onResourceDecoded(DataSource dataSource,
@NonNull Resource<Z> decoded) {
@SuppressWarnings("unchecked")
//1. 獲取數(shù)據(jù)資源的類型
Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass();
Transformation<Z> appliedTransformation = null;
Resource<Z> transformed = decoded;
//2. 若非從資源磁盤緩存中獲取的數(shù)據(jù)源, 則對資源進行 transformation 操作
if (dataSource != DataSource.RESOURCE_DISK_CACHE) {
appliedTransformation = decodeHelper.getTransformation(resourceSubClass);
transformed = appliedTransformation.transform(glideContext, decoded, width, height);
}
if (!decoded.equals(transformed)) {
decoded.recycle();
}
// 3. 構(gòu)建數(shù)據(jù)編碼的策略
final EncodeStrategy encodeStrategy;
final ResourceEncoder<Z> encoder;
if (decodeHelper.isResourceEncoderAvailable(transformed)) {
encoder = decodeHelper.getResultEncoder(transformed);
encodeStrategy = encoder.getEncodeStrategy(options);
} else {
encoder = null;
encodeStrategy = EncodeStrategy.NONE;
}
//4. 根據(jù)編碼策略, 構(gòu)建緩存的 key
Resource<Z> result = transformed;
boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey);
if (diskCacheStrategy.isResourceCacheable(isFromAlternateCacheKey, dataSource,
encodeStrategy)) {
if (encoder == null) {
throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass());
}
final Key key;
switch (encodeStrategy) {
case SOURCE:// 源數(shù)據(jù)的 key
key = new DataCacheKey(currentSourceKey, signature);
break;
case TRANSFORMED: // 資源數(shù)據(jù)的 key
key =
new ResourceCacheKey(
decodeHelper.getArrayPool(),
currentSourceKey,
signature,
width,
height,
appliedTransformation,
resourceSubClass,
options);
break;
default:
throw new IllegalArgumentException("Unknown strategy: " + encodeStrategy);
}
// 5. 初始化編碼管理者, 用于提交內(nèi)存緩存
LockedResource<Z> lockedResult = LockedResource.obtain(transformed);
deferredEncodeManager.init(key, encoder, lockedResult);
result = lockedResult;
}
// 返回 transform 之后的 bitmap
return result;
}
可以看到 onResourceDecoded 中, 主要是對中間資源做了如下的操作
- 對資源進行
transformed操作- 將資源轉(zhuǎn)為目標效果, 如在構(gòu)建
request時, 設(shè)置的CenterCrop
- 將資源轉(zhuǎn)為目標效果, 如在構(gòu)建
- 構(gòu)建磁盤緩存的
key
3. 將數(shù)據(jù)轉(zhuǎn)為目標格式
目標數(shù)據(jù)為 Drawable, 因此它的轉(zhuǎn)換器為 BitmapDrawableTranscoder
BitmapDrawableTranscoder .java
@Override
public Resource<BitmapDrawable> transcode(@NonNull Resource<Bitmap> toTranscode,
@NonNull Options options) {
//調(diào)用了 LazyBitmapDrawableResource.obtain 獲取 Resource<BitmapDrawable> 的實例對象
return LazyBitmapDrawableResource.obtain(resources, toTranscode);
}
LazyBitmapDrawableResource.java
public static Resource<BitmapDrawable> obtain(
@NonNull Resources resources, @Nullable Resource<Bitmap> bitmapResource) {
if (bitmapResource == null) {
return null;
}
//創(chuàng)建了一個 LazyBitmapDrawableResource
return new LazyBitmapDrawableResource(resources, bitmapResource);
}
private LazyBitmapDrawableResource(@NonNull Resources resources,
@NonNull Resource<Bitmap> bitmapResource) {
this.resources = Preconditions.checkNotNull(resources);
this.bitmapResource = Preconditions.checkNotNull(bitmapResource);
}
@Override
public BitmapDrawable get() {
// Get 方法反回了一個 BitmapDrawable 對象
return new BitmapDrawable(resources, bitmapResource.get());
}
好的, 轉(zhuǎn)化成目標數(shù)據(jù)也非常的簡單, 它將我們解析到的bitmap 存放到 LazyBitmapDrawableResource 內(nèi)部, 然后外界通過 get 方法就可以獲取到一個 BitmapDrawable 的對象了
4. 解碼轉(zhuǎn)換結(jié)構(gòu)圖

數(shù)據(jù)的展示
DecodeJob.java
private void decodeFromRetrievedData() {
...
Resource<R> resource = null;
try {
// 解析 inputStream 獲取資源
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
//通知外界資源獲取成功
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
if (resource instanceof Initializable) {
((Initializable) resource).initialize();
}
Resource<R> result = resource;
LockedResource<R> lockedResource = null;
if (deferredEncodeManager.hasResourceToEncode()) {
lockedResource = LockedResource.obtain(resource);
result = lockedResource;
}
// 回調(diào)上層資源
notifyComplete(result, dataSource);
stage = Stage.ENCODE;
try {
// 將數(shù)據(jù)緩存到磁盤
if (deferredEncodeManager.hasResourceToEncode()) {
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
if (lockedResource != null) {
lockedResource.unlock();
}
}
// Call onEncodeComplete outside the finally block so that it's not called if the encode process
// throws.
onEncodeComplete();
}
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
//從 DecodeJob 的構(gòu)建中, 我們知道這個 Callback 是一 EngineJob
callback.onResourceReady(resource, dataSource);
}
@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
}
notifyCallbacksOfResult();
}
DecodeJob.decodeFromRetrievedData 中, 主要做了兩個操作
- 回調(diào)
EngineJob.onResourceReady資源準備好了 - 將數(shù)據(jù)緩存到磁盤
EngineJob.java
void notifyCallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
Key localKey;
EngineResource<?> localResource;
...
// 1. 通知上層 Engine 任務(wù)完成了
engineJobListener.onEngineJobComplete(this, localKey, localResource);
//回調(diào)給 ImageViewTarget 展示資源
for (final ResourceCallbackAndExecutor entry : copy) {
entry.executor.execute(new CallResourceReady(entry.cb));
}
decrementPendingCallbacks();
}
-
EngineJob中也是有兩步操作, 一個是通知上層任務(wù)完成了, 另一個是回調(diào)給ImageViewTarget展示資源
Engine .java
public synchronized void onEngineJobComplete(
EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
// A null resource indicates that the load failed, usually due to an exception.
if (resource != null && resource.isMemoryCacheable()) {
// 將加載好的資源添加到內(nèi)存緩存
activeResources.activate(key, resource);
}
jobs.removeIfCurrent(key, engineJob);
}
我們知道在請求發(fā)起前是Engine嘗試通過內(nèi)存緩存讀, 結(jié)束之后再回到 Engine 添加內(nèi)存緩存也不足為奇了
ImageViewTarget.java
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);// 處理一些 transition 變化,
} else {
maybeUpdateAnimatable(resource);
}
}
private void setResourceInternal(@Nullable Z resource) {
// Order matters here. Set the resource first to make sure that the Drawable has a valid and
// non-null Callback before starting it.
setResource(resource);
maybeUpdateAnimatable(resource);
}
DrawableImageViewTarget .java
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
ImageViewTarget 調(diào)用了子類重寫的 setResource 方法, 將數(shù)據(jù)填充進去, 至此一次Glide圖像加載就完成了
流程回顧

通過一次流程分析我們得知, 整個Glide 圖片加載主要有如下幾步
- 請求管理器的構(gòu)建
- 一個
Context對應(yīng)一個RequestManager
- 一個
- 請求的構(gòu)建
- 請求的寬高、采樣的方式、
transform變化...
- 請求的寬高、采樣的方式、
- 通過請求獲取資源
-
Engine從內(nèi)存緩存中查找- 從
ActiveResources緩存中查找 - 從
LruResourceCache緩存中查找
- 從
- 內(nèi)存緩存不存在, 則構(gòu)建任務(wù)執(zhí)行
- 構(gòu)建一個
EngineJob描述一個請求任務(wù), 任務(wù)類型為DecodeJob-
DecodeJob從diskCache中查找 -
diskCache不存在, 則通過網(wǎng)絡(luò)請求, 獲取數(shù)據(jù)源 - 通過
Downsampler解析源數(shù)據(jù)并進行采樣壓縮獲取Bitmap - 對
Bitmap進行transform處理- 構(gòu)建磁盤緩存的
key
- 構(gòu)建磁盤緩存的
- 將
transform之后的Bitmap轉(zhuǎn)為Resource回傳給上層-
DecodeJob進行磁盤緩存
-
-
- 構(gòu)建一個
-
Engine對資源進行內(nèi)存緩存
-
- 傳遞給
View進行展示
看了 Glide 的加載流程, 我似乎能夠明白為什么他是 Google 推薦的圖片加載框架了, 內(nèi)部細節(jié)的處理做的非常的到位, 而且使用GlideContext用于描述Glide 的上下文, 與 Android 的 Context巧妙的融合在一起, 讀起來真有一種閱讀 Android 源碼的既視感
不過這只是最簡單的流程, 而且 Glide 支持 Gif, 視頻加載操作, 可想而知其內(nèi)部的 Decorder 處理了多少邏輯代碼, 如此復(fù)雜的流程, 嵌套了如此之多的回調(diào), 無疑增加了我們閱讀源碼的難度, 若是將這些操作分層, 并且使用攔截器去實現(xiàn), 我想定會讓一次圖像加載操作變得更加清晰明了
