
前言
-
Glide,該功能非常強(qiáng)大Android圖片加載開源框架 相信大家并不陌生
Github截圖 正由于他的功能強(qiáng)大,所以它的源碼非常復(fù)雜,這導(dǎo)致很多人望而卻步
本人嘗試將
Glide的功能進(jìn)行分解,并單獨(dú)針對每個(gè)功能進(jìn)行源碼分析,從而降低Glide源碼的復(fù)雜度。
接下來,我將推出一系列關(guān)于
Glide的功能源碼分析,有興趣可以繼續(xù)關(guān)注
- 今天,我將主要源碼分析
Glide的基礎(chǔ)功能:圖片加載 ,希望你們會喜歡。
由于文章較長,希望讀者先收藏 & 預(yù)留足夠時(shí)間進(jìn)行查看。
目錄

1. 簡介
- 定義:
Google開發(fā)者Sam sjudd出品的 一個(gè)Android開源庫 - 作用:圖片加載
- 具體功能列表

注:從上面可看出,Glide不僅解決了 圖片異步加載 的問題,還解決了Android加載圖片時(shí)的一些常見問題,功能十分強(qiáng)大。
2. 與主流圖片開源庫對比
關(guān)于Glide與主流圖片開源庫(Universal-Image-Loader、Picasso、Fresco),請看文章:3分鐘全面了解Android主流圖片加載庫
3. 具體使用
關(guān)于Glide的各種使用方法,請看文章:Android圖片加載庫:最全面解析Glide用法
4. 源碼分析
在進(jìn)行源碼分析前,有幾點(diǎn)需要特別說明:
- 本次源碼分析是基于
Glide 3.7.0,版本下載地址 - 本次源碼分析是主要分析
Glide的基本功能:圖片加載,所以關(guān)于其他功能的代碼本文一律忽略
因?yàn)?code>Glide的功能實(shí)在太多了,所以源碼非常復(fù)雜,無法同時(shí)分析多個(gè)功能。但其他功能將下
Glide的系列文章繼續(xù)分析。
-
Glide源碼較為難懂、難分析的其中一個(gè)原因是:許多對象都是很早之前就初始化好,而并非在使用前才初始化。所以當(dāng)真正使用該對象時(shí),開發(fā)者可能已經(jīng)忘記是在哪里初始化、該對象是作什么用的了。所以本文會在每個(gè)階段進(jìn)行一次總結(jié),而讀者則需要經(jīng)常往返看該總結(jié),從而解決上述問題。
下面,我們將根據(jù) Glide 的加載圖片的使用步驟一步步源碼分析。
-
Glide的使用步驟如下:
Glide.with(this).load(url).into(imageView);
// 參數(shù)說明
// 參數(shù)1:Context context
// Context對于很多Android API的調(diào)用都是必須的,這里就不多說了
// 參數(shù)2:String imageUrl:被加載圖像的Url地址
// 大多情況下,一個(gè)字符串代表一個(gè)網(wǎng)絡(luò)圖片的URL
// 參數(shù)3:ImageView targetImageView:圖片最終要展示的地方。
- 所以
Glide的源碼分析分為三步:.with().load().into()
4.1 with()
定義:
Glide類中的靜態(tài)方法,根據(jù)傳入 不同參數(shù) 進(jìn)行 方法重載-
作用:
- 得到一個(gè)
RequestManager對象 - 根據(jù)傳入
with()方法的參數(shù) 將Glide圖片加載的生命周期與Activity/Fragment的生命周期進(jìn)行綁定,從而實(shí)現(xiàn)自動執(zhí)行請求,暫停操作
- 得到一個(gè)
下面先說明一些重要對象名

- 具體源碼
public class Glide {
...
// with()重載種類非常多,根據(jù)傳入的參數(shù)可分為:
// 1. 非Application類型的參數(shù)(Activity & Fragment )
// 2. Application類型的參數(shù)(Context)
// 下面將詳細(xì)分析
// 參數(shù)1:Application類型
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
// 步驟1:調(diào)用RequestManagerRetriever類的靜態(tài)get()獲得RequestManagerRetriever對象 - 單例實(shí)現(xiàn)
return retriever.get(context);
// 步驟2:調(diào)用RequestManagerRetriever實(shí)例的get()獲取RequestManager對象 & 綁定圖片加載的生命周期 ->>分析1
}
// 參數(shù)2:非Application類型(Activity & Fragment )
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
public static RequestManager with(Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static RequestManager with(android.app.Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
}
}
<-- 分析1:RequestManagerRetriever對象的實(shí)例 get()-->
// 作用:
// 1. 獲取RequestManager對象
// 2. 將圖片加載的生命周期與Activity/Fragment的生命周期進(jìn)行綁定
public class RequestManagerRetriever implements Handler.Callback {
...
// 實(shí)例的get()重載種類很多,參數(shù)分為:(與with()類似)
// 1. Application類型(Context)
// 2. 非Application類型(Activity & Fragment )- >>分析3
// 下面會詳細(xì)分析
// 參數(shù)1:Application類型(Context)
public RequestManager get(Context context) {
return getApplicationManager(context);
// 調(diào)用getApplicationManager()最終獲取一個(gè)RequestManager對象 ->>分析2
// 因?yàn)锳pplication對象的生命周期即App的生命周期
// 所以Glide加載圖片的生命周期是自動與應(yīng)用程序的生命周期綁定,不需要做特殊處理(若應(yīng)用程序關(guān)閉,Glide的加載也會終止)
}
// 參數(shù)2:非Application類型(Activity & Fragment )
// 將Glide加載圖片的生命周期與Activity生命周期同步的具體做法:向當(dāng)前的Activity添加一個(gè)隱藏的Fragment
// 原因:因Fragment的生命周期 與 Activity 的是同步的,通過添加隱藏的Fragment 從而監(jiān)聽Activity的生命周期,從而實(shí)現(xiàn)Glide加載圖片的生命周期與Activity的生命周期 進(jìn)行同步。
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RequestManager get(Activity activity) {
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
//判斷activity是否已經(jīng)銷毀
android.app.FragmentManager fm = activity.getFragmentManager();
// 獲取FragmentManager 對象
return fragmentGet(activity, fm);
// 通過fragmentGet返回RequestManager->>分析4
}
}
public RequestManager get(FragmentActivity activity) {
// 邏輯同上,此處不作過多描述
...
}
public RequestManager get(Fragment fragment) {
// 邏輯同上,此處不作過多描述
...
}
}
<-- 分析2:getApplicationManager(context)-->
private RequestManager getApplicationManager(Context context) {
...
Glide glide = Glide.get(context);
// 通過單例模式創(chuàng)建Glide實(shí)例 ->>分析3
applicationManager =
new RequestManager(
glide, new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
}
}
}
return applicationManager;
}
<-- 分析3:Glide.get(context) -->
public static Glide get(Context context) {
if (glide == null) {
// 單例模式的體現(xiàn)
synchronized (Glide.class) {
if (glide == null) {
Context applicationContext = context.getApplicationContext();
List<GlideModule> modules = new ManifestParser(applicationContext).parse();
// 解析清單文件配置的自定義GlideModule的metadata標(biāo)簽,返回一個(gè)GlideModule集合
GlideBuilder builder = new GlideBuilder(applicationContext);
// 步驟1:創(chuàng)建GlideBuilder對象
for (GlideModule module : modules) {
module.applyOptions(applicationContext, builder);
}
glide = builder.createGlide();
// 步驟2:根據(jù)GlideBuilder對象創(chuàng)建Glide實(shí)例
// GlideBuilder會為Glide設(shè)置一默認(rèn)配置,如:Engine,RequestOptions,GlideExecutor,MemorySizeCalculator
for (GlideModule module : modules) {
module.registerComponents(applicationContext, glide.registry);
// 步驟3:利用GlideModule 進(jìn)行延遲性的配置和ModelLoaders的注冊
}
}
}
}
return glide;
}
// 回到分析1 進(jìn)入 分析2的地方
<--分析4:fragmentGet() -->
// 作用:
// 1. 創(chuàng)建Fragment
// 2. 向當(dāng)前的Activity中添加一個(gè)隱藏的Fragment
// 3. 將RequestManager與該隱藏的Fragment進(jìn)行綁定
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
RequestManagerFragment current = getRequestManagerFragment(fm);
// 獲取RequestManagerFragment
// 作用:利用Fragment進(jìn)行請求的生命周期管理
RequestManager requestManager = current.getRequestManager();
// 若requestManager 為空,即首次加載初始化requestManager
if (requestManager == null) {
// 創(chuàng)建RequestManager傳入Lifecycle實(shí)現(xiàn)類,如ActivityFragmentLifecycle
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
// 調(diào)用setRequestManager設(shè)置到RequestManagerFragment
}
return requestManager;
}
總結(jié)
with()是為得到一個(gè)RequestManager對象 從而將Glide加載圖片周期 與Activity 和Fragment進(jìn)行綁定,從而管理Glide加載圖片周期
- 最終返回
RequestManager對象- 由于本文主要講解圖片加載的功能,所以關(guān)于加載圖片生命周期的內(nèi)容暫時(shí)不講解。
4.2 load()
定義
由于.with()返回的是一個(gè)RequestManager對象,所以 第2步中調(diào)用的是RequestManager類的load()作用
預(yù)先創(chuàng)建好對圖片進(jìn)行一系列操作(加載、編解碼、轉(zhuǎn)碼)的對象,并全部封裝到DrawableTypeRequest`對象中。
Glide支持加載 圖片的URL字符串、圖片本地路徑等,因此RequestManager類 存在load()的重載- 此處主要講解 最常見的加載圖片
URL字符串的load(),即load(String url)
- 具體過程
public class RequestManager implements LifecycleListener {
// 僅貼出關(guān)鍵代碼
...
public DrawableTypeRequest<String> load(String string) {
return (DrawableTypeRequest<String>) fromString().load(string);
// 先調(diào)用fromString()再調(diào)用load()
// load()作用:傳入圖片URL地址
// fromString()作用 ->>分析1
}
<-- 分析1:fromString()-->
public DrawableTypeRequest<String> fromString() {
return loadGeneric(String.class);
// loadGeneric()的作用 ->>分析2
}
<-- 分析2:loadGeneric()-->
private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
// 創(chuàng)建第1個(gè)ModelLoader對象;作用:加載圖片
// Glide會根據(jù)load()方法傳入不同類型參數(shù),得到不同的ModelLoader對象
// 此處傳入?yún)?shù)是String.class,因此得到的是StreamStringLoader對象(實(shí)現(xiàn)了ModelLoader接口)
ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader = Glide.buildFileDescriptorModelLoader(modelClass, context);
// 創(chuàng)建第2個(gè)ModelLoader對象,作用同上:加載圖片
// 此處得到的是FileDescriptorModelLoader對象
return optionsApplier.apply(
new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
glide, requestTracker, lifecycle, optionsApplier));
// 創(chuàng)建DrawableTypeRequest對象 & 傳入剛才創(chuàng)建的ModelLoader對象 和 其他初始化配置的參數(shù)
// DrawableTypeRequest類分析 ->>分析3
}
...
<-- 分析3:DrawableTypeRequest類()-->
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
// 關(guān)注1:構(gòu)造方法
DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
super(context, modelClass,
buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
GlideDrawable.class, null),
glide, requestTracker, lifecycle);
// 調(diào)用buildProvider()方法 -->分析4
// 并把上述創(chuàng)建的streamModelLoader和fileDescriptorModelLoader等參數(shù)傳入到buildProvider()中
// 關(guān)注2:DrawableTypeRequest類主要提供2個(gè)方法: asBitmap() & asGif()
// asBitmap()作用:強(qiáng)制加載 靜態(tài)圖片
public BitmapTypeRequest<ModelType> asBitmap() {
return optionsApplier.apply(new BitmapTypeRequest<ModelType>(this, streamModelLoader,
fileDescriptorModelLoader, optionsApplier));
// 創(chuàng)建BitmapTypeRequest對象
}
// asGif() 作用:強(qiáng)制加載 動態(tài)圖片
public GifTypeRequest<ModelType> asGif() {
return optionsApplier.apply(new GifTypeRequest<ModelType>(this, streamModelLoader, optionsApplier));
// 創(chuàng)建GifTypeRequest對象
// 注:若沒指定,則默認(rèn)使用DrawableTypeRequest
}
}
<-- 分析4:buildProvider()-->
private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
ModelLoader<A, InputStream> streamModelLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
Class<R> transcodedClass,
ResourceTranscoder<Z, R> transcoder) {
if (transcoder == null) {
transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
// 創(chuàng)建GifBitmapWrapperDrawableTranscoder對象(實(shí)現(xiàn)了ResourceTranscoder接口)
// 作用:對圖片進(jìn)行轉(zhuǎn)碼
}
DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
resourceClass);
// 創(chuàng)建ImageVideoGifDrawableLoadProvider對象(實(shí)現(xiàn)了DataLoadProvider接口)
// 作用:對圖片進(jìn)行編解碼
ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
fileDescriptorModelLoader);
// 創(chuàng)建ImageVideoModelLoader
// 并把上面創(chuàng)建的兩個(gè)ModelLoader:streamModelLoader和fileDescriptorModelLoader封裝到了ImageVideoModelLoader中
return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
// 創(chuàng)建FixedLoadProvider對象
// 把上面創(chuàng)建的GifBitmapWrapperDrawableTranscoder、ImageVideoModelLoader、ImageVideoGifDrawableLoadProvider都封裝進(jìn)去
// 注:FixedLoadProvider對象就是第3步into()中onSizeReady()的loadProvider對象
}
// 回到分析3的關(guān)注點(diǎn)2
- 在
RequestManager的load()中,通過fromString()最終返回一個(gè)DrawableTypeRequest對象,并調(diào)用該對象的load()傳入圖片的URL地址
請回看分析1上面的代碼
- 但從上面的分析3可看出,
DrawableTypeRequest類中并沒有load()和第3步需要分析的into(),所以load()和into()是在DrawableTypeRequest類的父類中:DrawableRequestBuilder類中。繼承關(guān)系如下:

public class DrawableRequestBuilder<ModelType>
extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
implements BitmapOptions, DrawableOptions {
...
// 最終load()方法返回的其實(shí)就是一個(gè)DrawableTypeRequest對象
@Override
public Target<GlideDrawable> into(ImageView view) {
return super.into(view);
}
// 特別注意:DrawableRequestBuilder類中有很多使用Glide的API方法,此處不做過多描述
}
至此,第2步的 load()分析完成
總結(jié)
load()中預(yù)先創(chuàng)建好對圖片進(jìn)行一系列操作(加載、編解碼、轉(zhuǎn)碼)的對象,并全部封裝到 DrawableTypeRequest對象中。

4.3 into()
- 作用:構(gòu)建網(wǎng)絡(luò)請求對象 并 執(zhí)行 該網(wǎng)絡(luò)請求
即 獲取圖片資源 & 加載圖片并顯示
-
總體邏輯如下:
示意圖 詳細(xì)過程:
在第2步的RequestManager的load()中,最終返回一個(gè)DrawableTypeRequest對象
封裝好了對圖片進(jìn)行一系列操作(加載、編解碼、轉(zhuǎn)碼)的對象
- 但
DrawableTypeRequest類中并沒有load()和第3步需要分析的into(),所以load()和into()是在DrawableTypeRequest類的父類中:DrawableRequestBuilder類
繼承關(guān)系如下

所以,第三步是調(diào)用DrawableRequestBuilder類的 into()完成圖片的最終加載。
public class DrawableRequestBuilder<ModelType>
extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
implements BitmapOptions, DrawableOptions {
@Override
public Target<GlideDrawable> into(ImageView view) {
return super.into(view);
// 調(diào)用DrawableRequestBuilder的父類GenericRequestBuilder的into() ->>分析1
}
}
<-- 分析1:GenericRequestBuilder類的into()-->
public class GenericRequestBuilder<ModelType> {
...
public Target<TranscodeType> into(ImageView view) {
// 判斷是否在主線程(跟新UI只能在主線程)
// 此處邏輯先不講解,后面會詳細(xì)說明,直接跳到方法的最后一行
Util.assertMainThread();
if (view == null) {
throw new IllegalArgumentException("You must pass in a non null View");
}
if (!isTransformationSet && view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
applyCenterCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
applyFitCenter();
break;
//$CASES-OMITTED$
default:
// Do nothing.
}
}
return into(glide.buildImageViewTarget(view, transcodeClass));
// 創(chuàng)建Target對象:用于最終展示圖片 ->>分析2
// 從分析3回來
}
}
<-- 分析2:buildImageViewTarget()-->
<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
// ->>分析3
}
<-- 分析3:ImageViewTargetFactory的buildTarget()-->
public class ImageViewTargetFactory {
public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
// 根據(jù)傳入的class參數(shù)構(gòu)建不同的Target對象,分為三種情況:
// 情況1:若加載圖片時(shí)調(diào)用了asBitmap(),那么構(gòu)建的是BitmapImageViewTarget對象
// 情況2:否則構(gòu)建的是GlideDrawableImageViewTarget對象
// 情況3:DrawableImageViewTarget對象基本用不到,此處忽略
// 具體請看以下代碼
if (GlideDrawable.class.isAssignableFrom(clazz)) {
return (Target<Z>) new GlideDrawableImageViewTarget(view);
} else 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)");
}
}
}

- 此處得到了
GlideDrawableImageViewTarget對象(大多數(shù)情況下) - 回到上面分析1 -
GenericRequestBuilder類的into()最后一行:將GlideDrawableImageViewTarget對象傳入到GenericRequestBuilder的into(Target target)中
我們繼續(xù)看 GenericRequestBuilder的into(Target target) 的源碼:
public <Y extends Target<TranscodeType>> Y into(Y target) {
Request request = buildRequest(target);
// 關(guān)注1:構(gòu)建Request對象:發(fā)出加載圖片請求
target.setRequest(request);
// 將請求設(shè)置到target
lifecycle.addListener(target);
// 將target加入到lifecycle
requestTracker.runRequest(request);
// 關(guān)注2:執(zhí)行網(wǎng)絡(luò)請求Request
return target;
}
- 此處是 發(fā)送加載圖片網(wǎng)絡(luò)請求
- 有2個(gè)關(guān)注點(diǎn):構(gòu)建
Request對象 & 執(zhí)行Request
4.3.1 構(gòu)建Request對象
- 作用
創(chuàng)建GenericRequest對象 & 初始化(即將load()中的API參數(shù)賦值到GenericRequest對象中)
<-- 分析4:buildRequest() -->
// 作用:構(gòu)建Request對象
private Request buildRequest(Target<TranscodeType> target) {
return buildRequestRecursive(target, null);
// 往下調(diào)用
}
private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
// 90%的代碼用于處理縮略圖,此處僅關(guān)注主流程,即如何構(gòu)建Request對象
// 僅貼出關(guān)鍵代碼(如何構(gòu)建Request對象)
...
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
// 往下調(diào)用
private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
RequestCoordinator requestCoordinator) {
return GenericRequest.obtain(
loadProvider,
model,
signature,
context,
priority,
target,
sizeMultiplier,
placeholderDrawable,
placeholderId,
errorPlaceholder,
errorId,
fallbackDrawable,
fallbackResource,
requestListener,
requestCoordinator,
glide.getEngine(),
transformation,
transcodeClass,
isCacheable,
animationFactory,
overrideWidth,
overrideHeight,
diskCacheStrategy);
// 調(diào)用了GenericRequest的obtain()
// 作用:將在load()中調(diào)用的所有API參數(shù)都組裝到Request對象當(dāng)中 -->分析5
}
<-- 分析5:GenericRequest的obtain() -->
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,
ResourceCallback {
// 僅貼出關(guān)鍵代碼
...
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(
LoadProvider<A, T, Z, R> loadProvider,
A model,
Key signature,
Context context,
Priority priority,
Target<R> target,
float sizeMultiplier,
Drawable placeholderDrawable,
int placeholderResourceId,
Drawable errorDrawable,
int errorResourceId,
Drawable fallbackDrawable,
int fallbackResourceId,
RequestListener<? super A, R> requestListener,
RequestCoordinator requestCoordinator,
Engine engine,
Transformation<Z> transformation,
Class<R> transcodeClass,
boolean isMemoryCacheable,
GlideAnimationFactory<R> animationFactory,
int overrideWidth,
int overrideHeight,
DiskCacheStrategy diskCacheStrategy) {
@SuppressWarnings("unchecked")
GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
if (request == null) {
request = new GenericRequest<A, T, Z, R>();
// 創(chuàng)建GenericRequest對象
}
// init()作用:將傳入的Load()中的API參數(shù)賦值到GenericRequest的成員變量
request.init(loadProvider,
model,
signature,
context,
priority,
target,
sizeMultiplier,
placeholderDrawable,
placeholderResourceId,
errorDrawable,
errorResourceId,
fallbackDrawable,
fallbackResourceId,
requestListener,
requestCoordinator,
engine,
transformation,
transcodeClass,
isMemoryCacheable,
animationFactory,
overrideWidth,
overrideHeight,
diskCacheStrategy);
return request;
// 返回GenericRequest對象
}
...
}
至此,一個(gè) 發(fā)送加載圖片的網(wǎng)絡(luò)請求 Request 對象GenericRequest 創(chuàng)建完畢。
本文主要針對圖片加載功能,關(guān)于發(fā)送加載圖片的網(wǎng)絡(luò)請求細(xì)節(jié)將在下篇文章進(jìn)行描述。
總結(jié)

4.3.2 執(zhí)行網(wǎng)絡(luò)請求對象Request
public <Y extends Target<TranscodeType>> Y into(Y target) {
Request request = buildRequest(target);
// 關(guān)注1:構(gòu)建Request對象:發(fā)出加載圖片請求
target.setRequest(request);
lifecycle.addListener(target);
requestTracker.runRequest(request);
// 關(guān)注2:執(zhí)行Request ->>分析6
return target;
}
/**
* 步驟1:加載前
**/
<-- 分析6:runRequest(request) -->
public void runRequest(Request request) {
// 此時(shí)的Request是GenericRequest對象
requests.add(request);
// 將每個(gè)提交的請求加入到一個(gè)set中:管理請求
// 判斷Glide當(dāng)前是否處于暫停狀態(tài)
if (!isPaused) {
// 若不處于暫停狀態(tài),則調(diào)用GenericRequest的begin()來執(zhí)行Request ->>分析7
request.begin();
} else {
// 若處于暫停,則先將Request添加到待執(zhí)行隊(duì)列里面,等暫停狀態(tài)解除后再執(zhí)行
pendingRequests.add(request);
}
}
/**
* 步驟2:加載時(shí)
**/
<-- 分析7:GenericRequest的begin() -->
public void begin() {
// 有2個(gè)關(guān)注點(diǎn)
// 關(guān)注1
// model = 第2步load()傳入的圖片URL地址
// 若model()等于null,會調(diào)用onException()
// onException()內(nèi)部調(diào)用setErrorPlaceholder()
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
// 關(guān)注2:
// 圖片加載情況分兩種:
// 1. 開發(fā)者使用了override() API為圖片指定了一個(gè)固定的寬高
// 2. 無使用
// 情況1:使用了override() API為圖片指定了一個(gè)固定的寬高
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
// 調(diào)用onSizeReady()加載
// 否則,則是情況2,調(diào)用target.getSize()
} else {
target.getSize(this);
// target.getSize()的內(nèi)部會根據(jù)ImageView的layout_width和layout_height值做一系列的計(jì)算,來算出圖片顯示的寬高
// 計(jì)算后,也會調(diào)用onSizeReady()方法進(jìn)行加載
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
// 從分析8看回來的:在圖片請求開始前,會先使用Loading占位圖代替最終的圖片顯示
}
}
在begin()方法中有兩個(gè)關(guān)注點(diǎn):
- 關(guān)注點(diǎn)1:若
model(第2步load()傳入的圖片URL地址)等于null,會調(diào)用onException() - 關(guān)注點(diǎn)2:圖片加載情況
下面將詳細(xì)說明
關(guān)注1
若model(第2步load()傳入的圖片URL地址)等于null,會調(diào)用onException()(內(nèi)部調(diào)用setErrorPlaceholder())
private void setErrorPlaceholder(Exception e) {
Drawable error = model == null ? getFallbackDrawable() : null;
// 若有error的占位圖,則采用先獲取error的占位圖
if (error == null) {
error = getErrorDrawable();
}
// 若沒有error的占位圖,則再去獲取一個(gè)loading占位圖
if (error == null) {
error = getPlaceholderDrawable();
}
target.onLoadFailed(e, error);
// 將占位圖(error / loading)傳入到onLoadFailed()中 ->>分析8
}
<-- 分析8:onLoadFailed() -->
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter {
...
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
view.setImageDrawable(errorDrawable);
// 將該error占位圖顯示到ImageView
}
@Override
public void onLoadStarted(Drawable placeholder) {
view.setImageDrawable(placeholder);
// 在圖片請求開始前,會先使用Loading占位圖代替最終的圖片顯示
// 在begin()時(shí)調(diào)用(回看分析7)
}
...
}
所以此處顯示出Glide的用法:
- 若傳入圖片的
url為Null,會采用error / loading的占位圖進(jìn)行代替 - 圖片請求開始前,會先使用
Loading占位圖 代替 最終的圖片顯示
關(guān)注2
圖片加載情況(重點(diǎn)關(guān)注)
<-- 分析7:GenericRequest的begin() -->
public void begin() {
// 關(guān)注1(請?zhí)^,直接看關(guān)注2)
// 若model(第2步load()傳入的圖片URL地址)等于null,會調(diào)用onException()
// onException()內(nèi)部調(diào)用setErrorPlaceholder()
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
// 關(guān)注2:
// 圖片加載情況分兩種:
// 1. 為圖片指定加載固定的寬高(使用override() 的API)
// 2. 無指定加載的寬高
// 情況1:為圖片指定加載固定的寬高(使用override() 的API)
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
// 調(diào)用onSizeReady()加載->>分析9
// 否則,則是情況2:無指定加載的寬高
} else {
target.getSize(this);
// target.getSize()會根據(jù)ImageView的layout_width和layout_height值做一系列的計(jì)算,來算出圖片顯示的寬高
// 計(jì)算后,最終也會調(diào)用onSizeReady()進(jìn)行加載
}
}
<-- 分析9:onSizeReady()-->
public void onSizeReady(int width, int height) {
// loadProvider 對象 即 第2步load()中的FixedLoadProvider對象
// 里面封裝了GifBitmapWrapperDrawableTranscoder、ImageVideoModelLoader、ImageVideoGifDrawableLoadProvider對象)
// ->>請回看第2步load()中的 分析3:DrawableTypeRequest類
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
// 從loadProvider 對象中獲取ImageVideoModelLoader對象
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
// 從loadProvider 對象中獲取GifBitmapWrapperDrawableTranscoder對象
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
// ->>分析10
// 創(chuàng)建ImageVideoFetcher對象(傳入HttpUrlFetcher對象)
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
// 將上述獲得的ImageVideoFetcher、GifBitmapWrapperDrawableTranscoder等一起傳入到了Engine的load()方法中 ->>分析11
}
...
}
<--分析10:ImageVideoModelLoader的getResourceFetcher() -->
public class ImageVideoModelLoader<A> implements ModelLoader<A, ImageVideoWrapper> {
@Override
public DataFetcher<ImageVideoWrapper> getResourceFetcher(A model, int width, int height) {
DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher = null;
if (fileDescriptorLoader != null) {
fileDescriptorFetcher = fileDescriptorLoader.getResourceFetcher(model, width, height);
// fileDescriptorLoader是在第2步load()中創(chuàng)建的FileDescriptorModelLoader:用于加載圖片
// 調(diào)用FileDescriptorModelLoader的getResourceFetcher()會得到一個(gè)HttpUrlFetcher對象
}
DataFetcher<InputStream> streamFetcher = null;
if (streamLoader != null) {
streamFetcher = streamLoader.getResourceFetcher(model, width, height);
// streamLoader是在第2步load()中創(chuàng)建的StreamStringLoader:用于加載圖片
// 調(diào)用streamLoader的getResourceFetcher()會得到一個(gè)HttpUrlFetcher對象
}
if (streamFetcher != null || fileDescriptorFetcher != null) {
return new ImageVideoFetcher(streamFetcher, fileDescriptorFetcher);
// 創(chuàng)建ImageVideoFetcher對象,并把上述獲得的2個(gè)HttpUrlFetcher對象傳進(jìn)去
// 即調(diào)用ImageVideoModelLoader的getResourceFetcher()得到的是ImageVideoFetcher
} else {
return null;
}
}
}
// 回到分析9原處
<-- 分析11:Engine的load() -->
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
...
// 省略關(guān)鍵代碼
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
// 創(chuàng)建EngineJob對象
// 作用:開啟線程(作異步加載圖片)
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
// 創(chuàng)建DecodeJob對象
// 作用:對圖片解碼(較復(fù)雜,下面會詳細(xì)說明)
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
// 創(chuàng)建EngineRunnable對象
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
// 執(zhí)行EngineRunnable對象
// 即在子線程中執(zhí)行EngineRunnable的run()方法 ->>分析12
return new LoadStatus(cb, engineJob);
}
...
}
<--分析12:EngineRunnable的run() -->
@Override
public void run() {
try {
resource = decode();
// 調(diào)用decode() 并 返回了一個(gè)Resource對象 ->>分析13
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception decoding", e);
}
...
}
<--分析13:decode() -->
private Resource<?> decode() throws Exception {
// 分兩種情況:從緩存當(dāng)中讀(解碼)圖片 & 不從緩存中讀(解碼)圖片
if (isDecodingFromCache()) {
// 若從緩存中decode圖片:執(zhí)行decodeFromCache()
// 本文先不討論緩存情況
return decodeFromCache();
} else {
// 不從緩存中讀(解碼)圖片:執(zhí)行decodeFromSource() ->>分析14
return decodeFromSource();
}
}
<--分析14:decodeFromSource() -->
private Resource<?> decodeFromSource() throws Exception {
return decodeJob.decodeFromSource();
// 調(diào)用了DecodeJob的decodeFromSource()方法 ->>分析15
}
<--分析15:DecodeJob.decodeFromSource() -->
class DecodeJob<A, T, Z> {
...
public Resource<Z> decodeFromSource() throws Exception {
Resource<T> decoded = decodeSource();
// 獲得Resource對象 ->>分析16
return transformEncodeAndTranscode(decoded);
// 調(diào)用transformEncodeAndTranscode()方法來處理該Resource對象。
}
<--分析16: decodeSource() -->
private Resource<T> decodeSource() throws Exception {
...
try {
final A data = fetcher.loadData(priority);
// 該fetcher是在分析10:onSizeReady()中得到的ImageVideoFetcher對象
// 即調(diào)用ImageVideoFetcher的loadData() - >>分析17
// 從分析17回來時(shí)看這里:
decoded = decodeFromSourceData(data);
// 將分析17創(chuàng)建的ImageVideoWrapper對象傳入到decodeFromSourceData(),解碼該對象 -->分析19
}
...
}
<--分析17: fetcher.loadData() -->
@Override
public ImageVideoWrapper loadData(Priority priority) throws Exception {
InputStream is = null;
if (streamFetcher != null) {
try {
is = streamFetcher.loadData(priority);
// 該streamFetcher是創(chuàng)建ImageVideoFetcher對象時(shí)傳入的HttpUrlFetcher
// 因此這里調(diào)用的是HttpUrlFetcher的loadData() ->>分析18
} catch (Exception e) {
return new ImageVideoWrapper(is, fileDescriptor);
// 從分析18回來時(shí)看這里
// 創(chuàng)建ImageVideoWrapper對象 & 傳入分析18創(chuàng)建的InputStream ->>回到分析16
}
<--分析18:HttpUrlFetcher的loadData() -->
// 此處是網(wǎng)絡(luò)請求的代碼
public class HttpUrlFetcher implements DataFetcher<InputStream> {
@Override
public InputStream loadData(Priority priority) throws Exception {
return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
// 繼續(xù)往下看
}
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers)
...
// 靜態(tài)工廠模式創(chuàng)建HttpURLConnection對象
urlConnection = connectionFactory.build(url);
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
//設(shè)置請求參數(shù)
//設(shè)置連接超時(shí)時(shí)間2500ms
urlConnection.setConnectTimeout(2500);
//設(shè)置讀取超時(shí)時(shí)間2500ms
urlConnection.setReadTimeout(2500);
//不使用http緩存
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
// Connect explicitly to avoid errors in decoders if connection fails.
urlConnection.connect();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (statusCode / 100 == 2) {
//請求成功
return getStreamForSuccessfulRequest(urlConnection);
// 繼續(xù)往下看
}
}
private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
throws IOException {
if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
int contentLength = urlConnection.getContentLength();
stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Got non empty content encoding: " + urlConnection.getContentEncoding());
}
stream = urlConnection.getInputStream();
}
return stream;
// 最終返回InputStream對象(但還沒開始讀取數(shù)據(jù))
// 回到分析17中的最后一行
}
}
}
分析19:圖片的解碼
<--分析19:decodeFromSourceData()() -->
private Resource<T> decodeFromSourceData(A data) throws IOException {
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
// 調(diào)用loadProvider.getSourceDecoder()得到的是GifBitmapWrapperResourceDecoder對象
// 即調(diào)用GifBitmapWrapperResourceDecoder對象的decode()來對圖片進(jìn)行解碼 ->>分析20
return decoded;
}
<--分析20:GifBitmapWrapperResourceDecoder對象的decode() -->
public class GifBitmapWrapperResourceDecoder implements ResourceDecoder<ImageVideoWrapper, GifBitmapWrapper> {
...
@Override
public Resource<GifBitmapWrapper> decode(ImageVideoWrapper source, int width, int height) throws IOException {
wrapper = decode(source, width, height, tempBytes);
// 傳入?yún)?shù),并調(diào)用了另外一個(gè)decode()進(jìn)行重載 ->>分析21
}
<--分析21:重載的decode() -->
private GifBitmapWrapper decode(ImageVideoWrapper source, int width, int height, byte[] bytes) throws IOException {
final GifBitmapWrapper result;
if (source.getStream() != null) {
result = decodeStream(source, width, height, bytes);
// 作用:從服務(wù)器返回的流當(dāng)中讀取數(shù)據(jù)- >>分析22
} else {
result = decodeBitmapWrapper(source, width, height);
}
return result;
}
<--分析22:decodeStream() -->
// 作用:從服務(wù)器返回的流當(dāng)中讀取數(shù)據(jù)
// 讀取方式:
// 1. 從流中讀取2個(gè)字節(jié)的數(shù)據(jù):判斷該圖是GIF圖還是普通的靜圖
// 2. 若是GIF圖,就調(diào)用decodeGifWrapper() 解碼
// 3. 若普通靜圖,就調(diào)用decodeBitmapWrapper() 解碼
// 此處僅分析 對于靜圖解碼
private GifBitmapWrapper decodeStream(ImageVideoWrapper source, int width, int height, byte[] bytes)
throws IOException {
// 步驟1:從流中讀取兩個(gè)2字節(jié)數(shù)據(jù)進(jìn)行圖片類型的判斷
InputStream bis = streamFactory.build(source.getStream(), bytes);
bis.mark(MARK_LIMIT_BYTES);
ImageHeaderParser.ImageType type = parser.parse(bis);
bis.reset();
GifBitmapWrapper result = null;
// 步驟2:若是GIF圖,就調(diào)用decodeGifWrapper() 解碼
if (type == ImageHeaderParser.ImageType.GIF) {
result = decodeGifWrapper(bis, width, height);
}
// 步驟3:若是普通靜圖,就調(diào)用decodeBitmapWrapper()解碼
if (result == null) {
ImageVideoWrapper forBitmapDecoder = new ImageVideoWrapper(bis, source.getFileDescriptor());
result = decodeBitmapWrapper(forBitmapDecoder, width, height);
// ->>分析23
}
return result;
}
<-- 分析23:decodeBitmapWrapper() -->
private GifBitmapWrapper decodeBitmapWrapper(ImageVideoWrapper toDecode, int width, int height) throws IOException {
GifBitmapWrapper result = null;
Resource<Bitmap> bitmapResource = bitmapDecoder.decode(toDecode, width, height);
// bitmapDecoder是一個(gè)ImageVideoBitmapDecoder對象
// 即調(diào)用ImageVideoBitmapDecoder對象的decode()->>分析24
if (bitmapResource != null) {
result = new GifBitmapWrapper(bitmapResource, null);
}
return result;
}
...
}
<-- 分析24:ImageVideoBitmapDecoder.decode() -->
public class ImageVideoBitmapDecoder implements ResourceDecoder<ImageVideoWrapper, Bitmap> {
...
@Override
public Resource<Bitmap> decode(ImageVideoWrapper source, int width, int height) throws IOException {
Resource<Bitmap> result = null;
InputStream is = source.getStream();
// 步驟1:獲取到服務(wù)器返回的InputStream
if (is != null) {
try {
result = streamDecoder.decode(is, width, height);
// 步驟2:調(diào)用streamDecoder.decode()進(jìn)行解碼
// streamDecode是一個(gè)StreamBitmapDecoder對象 ->>分析25
} catch (IOException e) {
...
}
<-- 分析25:StreamBitmapDecoder.decode() -->
public class StreamBitmapDecoder implements ResourceDecoder<InputStream, Bitmap> {
...
@Override
public Resource<Bitmap> decode(InputStream source, int width, int height) {
Bitmap bitmap = downsampler.decode(source, bitmapPool, width, height, decodeFormat);
// Downsampler的decode() ->>分析26
// 從分析26回來看這里:
return BitmapResource.obtain(bitmap, bitmapPool);
// 作用:將分析26中返回的Bitmap對象包裝成Resource<Bitmap>對象
// 因?yàn)閐ecode()返回的是一個(gè)Resource<Bitmap>對象;而從Downsampler中得到的是一個(gè)Bitmap對象,需要進(jìn)行類型的轉(zhuǎn)換
// 經(jīng)過這樣一層包裝后,如果還需要獲取Bitmap,只需要調(diào)用Resource<Bitmap>的get()即可
// 接下來,我們需要一層層地向上返回(請向下看直到跳出該代碼塊)
}
...
}
<-- 分析26:downsampler.decode() -->
// 主要作用:讀取服務(wù)器返回的InputStream & 加載圖片
// 其他作用:對圖片的壓縮、旋轉(zhuǎn)、圓角等邏輯處理
public abstract class Downsampler implements BitmapDecoder<InputStream> {
...
@Override
public Bitmap decode(InputStream is, BitmapPool pool, int outWidth, int outHeight, DecodeFormat decodeFormat) {
final ByteArrayPool byteArrayPool = ByteArrayPool.get();
final byte[] bytesForOptions = byteArrayPool.getBytes();
final byte[] bytesForStream = byteArrayPool.getBytes();
final BitmapFactory.Options options = getDefaultOptions();
// Use to fix the mark limit to avoid allocating buffers that fit entire images.
RecyclableBufferedInputStream bufferedStream = new RecyclableBufferedInputStream(
is, bytesForStream);
// Use to retrieve exceptions thrown while reading.
// TODO(#126): when the framework no longer returns partially decoded Bitmaps or provides a way to determine
// if a Bitmap is partially decoded, consider removing.
ExceptionCatchingInputStream exceptionStream =
ExceptionCatchingInputStream.obtain(bufferedStream);
// Use to read data.
// Ensures that we can always reset after reading an image header so that we can still attempt to decode the
// full image even when the header decode fails and/or overflows our read buffer. See #283.
MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream);
try {
exceptionStream.mark(MARK_POSITION);
int orientation = 0;
try {
orientation = new ImageHeaderParser(exceptionStream).getOrientation();
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Cannot determine the image orientation from header", e);
}
} finally {
try {
exceptionStream.reset();
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Cannot reset the input stream", e);
}
}
}
options.inTempStorage = bytesForOptions;
final int[] inDimens = getDimensions(invalidatingStream, bufferedStream, options);
final int inWidth = inDimens[0];
final int inHeight = inDimens[1];
final int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation);
final int sampleSize = getRoundedSampleSize(degreesToRotate, inWidth, inHeight, outWidth, outHeight);
final Bitmap downsampled =
downsampleWithSize(invalidatingStream, bufferedStream, options, pool, inWidth, inHeight, sampleSize,
decodeFormat);
// BitmapFactory swallows exceptions during decodes and in some cases when inBitmap is non null, may catch
// and log a stack trace but still return a non null bitmap. To avoid displaying partially decoded bitmaps,
// we catch exceptions reading from the stream in our ExceptionCatchingInputStream and throw them here.
final Exception streamException = exceptionStream.getException();
if (streamException != null) {
throw new RuntimeException(streamException);
}
Bitmap rotated = null;
if (downsampled != null) {
rotated = TransformationUtils.rotateImageExif(downsampled, pool, orientation);
if (!downsampled.equals(rotated) && !pool.put(downsampled)) {
downsampled.recycle();
}
}
return rotated;
} finally {
byteArrayPool.releaseBytes(bytesForOptions);
byteArrayPool.releaseBytes(bytesForStream);
exceptionStream.release();
releaseOptions(options);
}
}
private Bitmap downsampleWithSize(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream,
BitmapFactory.Options options, BitmapPool pool, int inWidth, int inHeight, int sampleSize,
DecodeFormat decodeFormat) {
// Prior to KitKat, the inBitmap size must exactly match the size of the bitmap we're decoding.
Bitmap.Config config = getConfig(is, decodeFormat);
options.inSampleSize = sampleSize;
options.inPreferredConfig = config;
if ((options.inSampleSize == 1 || Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) && shouldUsePool(is)) {
int targetWidth = (int) Math.ceil(inWidth / (double) sampleSize);
int targetHeight = (int) Math.ceil(inHeight / (double) sampleSize);
// BitmapFactory will clear out the Bitmap before writing to it, so getDirty is safe.
setInBitmap(options, pool.getDirty(targetWidth, targetHeight, config));
}
return decodeStream(is, bufferedStream, options);
}
/**
* A method for getting the dimensions of an image from the given InputStream.
*
* @param is The InputStream representing the image.
* @param options The options to pass to
* {@link BitmapFactory#decodeStream(InputStream, android.graphics.Rect,
* BitmapFactory.Options)}.
* @return an array containing the dimensions of the image in the form {width, height}.
*/
public int[] getDimensions(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream,
BitmapFactory.Options options) {
options.inJustDecodeBounds = true;
decodeStream(is, bufferedStream, options);
options.inJustDecodeBounds = false;
return new int[] { options.outWidth, options.outHeight };
}
private static Bitmap decodeStream(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream,
BitmapFactory.Options options) {
if (options.inJustDecodeBounds) {
// This is large, but jpeg headers are not size bounded so we need something large enough to minimize
// the possibility of not being able to fit enough of the header in the buffer to get the image size so
// that we don't fail to load images. The BufferedInputStream will create a new buffer of 2x the
// original size each time we use up the buffer space without passing the mark so this is a maximum
// bound on the buffer size, not a default. Most of the time we won't go past our pre-allocated 16kb.
is.mark(MARK_POSITION);
} else {
// Once we've read the image header, we no longer need to allow the buffer to expand in size. To avoid
// unnecessary allocations reading image data, we fix the mark limit so that it is no larger than our
// current buffer size here. See issue #225.
bufferedStream.fixMarkLimit();
}
final Bitmap result = BitmapFactory.decodeStream(is, null, options);
return result;
// decode()方法執(zhí)行后會返回一個(gè)Bitmap對象
// 此時(shí)圖片已經(jīng)被加載出來
// 接下來的工作是讓加載了的Bitmap顯示到界面上
// 請回到分析25
}
...
}
步驟3:返回圖片資源
加載完圖片后,需要一層層向上返回
返回路徑
StreamBitmapDecoder(分析25)->ImageVideoBitmapDecoder(分析24)->GifBitmapWrapperResourceDecoder``decodeBitmapWrapper()(分析23)由于隔得太遠(yuǎn),我重新把(分析23)
decodeBitmapWrapper()貼出
<-- 分析23:decodeBitmapWrapper -->
private GifBitmapWrapper decodeBitmapWrapper(ImageVideoWrapper toDecode, int width, int height) throws IOException {
GifBitmapWrapper result = null;
Resource<Bitmap> bitmapResource = bitmapDecoder.decode(toDecode, width, height);
if (bitmapResource != null) {
result = new GifBitmapWrapper(bitmapResource, null);
// 將Resource<Bitmap>封裝到了一個(gè)GifBitmapWrapper對象
}
return result;
// 最終返回的是一個(gè)GifBitmapWrapper對象:既能封裝GIF,又能封裝Bitmap,從而保證了不管是什么類型的圖片,Glide都能加載
// 接下來我們分析下GifBitmapWrapper() ->>分析27
}
<-- 分析27:GifBitmapWrapper() -->
// 作用:分別對gifResource和bitmapResource做了一層封裝
public class GifBitmapWrapper {
private final Resource<GifDrawable> gifResource;
private final Resource<Bitmap> bitmapResource;
public GifBitmapWrapper(Resource<Bitmap> bitmapResource, Resource<GifDrawable> gifResource) {
if (bitmapResource != null && gifResource != null) {
throw new IllegalArgumentException("Can only contain either a bitmap resource or a gif resource, not both");
}
if (bitmapResource == null && gifResource == null) {
throw new IllegalArgumentException("Must contain either a bitmap resource or a gif resource");
}
this.bitmapResource = bitmapResource;
this.gifResource = gifResource;
}
/**
* Returns the size of the wrapped resource.
*/
public int getSize() {
if (bitmapResource != null) {
return bitmapResource.getSize();
} else {
return gifResource.getSize();
}
}
/**
* Returns the wrapped {@link Bitmap} resource if it exists, or null.
*/
public Resource<Bitmap> getBitmapResource() {
return bitmapResource;
}
/**
* Returns the wrapped {@link GifDrawable} resource if it exists, or null.
*/
public Resource<GifDrawable> getGifResource() {
return gifResource;
}
}
- 然后該
GifBitmapWrapper對象會一直向上返回 - 直到返回到
GifBitmapWrapperResourceDecoder的decode()時(shí)(分析20),會對GifBitmapWrapper對象再做一次封裝,如下所示:
此處將上面的分析20再次粘貼過來
<--分析20:GifBitmapWrapperResourceDecoder對象的decode() -->
public class GifBitmapWrapperResourceDecoder implements ResourceDecoder<ImageVideoWrapper, GifBitmapWrapper> {
...
@Override
public Resource<GifBitmapWrapper> decode(ImageVideoWrapper source, int width, int height) throws IOException {
try {
wrapper = decode(source, width, height, tempBytes);
} finally {
pool.releaseBytes(tempBytes);
}
// 直接看這里
return wrapper != null ? new GifBitmapWrapperResource(wrapper) : null;
// 將GifBitmapWrapper封裝到一個(gè)GifBitmapWrapperResource對象中(Resource<GifBitmapWrapper>類型) 并返回
// 該GifBitmapWrapperResource和上述的BitmapResource類似- 實(shí)現(xiàn)了Resource接口,可通過get()來獲取封裝的具體內(nèi)容
// GifBitmapWrapperResource()源碼分析 - >>分析28
}
<-- 分析28: GifBitmapWrapperResource()-->
// 作用:經(jīng)過這層封裝后,我們從網(wǎng)絡(luò)上得到的圖片就能夠以Resource接口的形式返回,并且還能同時(shí)處理Bitmap圖片和GIF圖片這兩種情況。
public class GifBitmapWrapperResource implements Resource<GifBitmapWrapper> {
private final GifBitmapWrapper data;
public GifBitmapWrapperResource(GifBitmapWrapper data) {
if (data == null) {
throw new NullPointerException("Data must not be null");
}
this.data = data;
}
@Override
public GifBitmapWrapper get() {
return data;
}
@Override
public int getSize() {
return data.getSize();
}
@Override
public void recycle() {
Resource<Bitmap> bitmapResource = data.getBitmapResource();
if (bitmapResource != null) {
bitmapResource.recycle();
}
Resource<GifDrawable> gifDataResource = data.getGifResource();
if (gifDataResource != null) {
gifDataResource.recycle();
}
}
}
繼續(xù)返回到DecodeJob的decodeFromSourceData()(分析19)中:
<-- 分析19:decodeFromSourceData()() -->
private Resource<T> decodeFromSourceData(A data) throws IOException {
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
return decoded;
// 該方法返回的是一個(gè)`Resource<T>`對象,其實(shí)就是Resource<GifBitmapWrapper>對象
}
- 繼續(xù)向上返回,最終返回到
DecodeJob的decodeFromSource()中(分析15) - 如下所示:
<-- 分析15:DecodeJob的decodeFromSource() -->
class DecodeJob<A, T, Z> {
...
public Resource<Z> decodeFromSource() throws Exception {
Resource<T> decoded = decodeSource();
// 返回到這里,最終得到了這個(gè)Resource<T>對象,即Resource<GifBitmapWrapper>對象
return transformEncodeAndTranscode(decoded);
// 作用:將該Resource<T>對象 轉(zhuǎn)換成 Resource<Z>對象 -->分析29
}
<--分析29:transformEncodeAndTranscode() -->
private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
Resource<Z> result = transcode(transformed);
// 把Resource<T>對象轉(zhuǎn)換成Resource<Z>對象 ->>分析30
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transcoded transformed from source", startTime);
}
return result;
}
<-- 分析30:transcode(transformed) -->
private Resource<Z> transcode(Resource<T> transformed) {
if (transformed == null) {
return null;
}
return transcoder.transcode(transformed);
// 調(diào)用了transcoder的transcode()
// 這里的transcoder就是第二步load()中的GifBitmapWrapperDrawableTranscoder對象(回看下第2步生成對象的表)
// 接下來請看 ->>分析31
}
<-- 分析31:GifBitmapWrapperDrawableTranscoder.transcode(transformed) -->
// 作用:轉(zhuǎn)碼,即從Resource<GifBitmapWrapper>中取出GifBitmapWrapper對象,然后再從GifBitmapWrapper中取出Resource<Bitmap>對象。
// 因?yàn)镚ifBitmapWrapper是無法直接顯示到ImageView上的,只有Bitmap或者Drawable才能顯示到ImageView上。
public class GifBitmapWrapperDrawableTranscoder implements ResourceTranscoder<GifBitmapWrapper, GlideDrawable> {
...
@Override
public Resource<GlideDrawable> transcode(Resource<GifBitmapWrapper> toTranscode) {
GifBitmapWrapper gifBitmap = toTranscode.get();
// 步驟1:從Resource<GifBitmapWrapper>中取出GifBitmapWrapper對象(上面提到的調(diào)用get()進(jìn)行提?。? Resource<Bitmap> bitmapResource = gifBitmap.getBitmapResource();
// 步驟2:從GifBitmapWrapper中取出Resource<Bitmap>對象
final Resource<? extends GlideDrawable> result;
// 接下來做了一個(gè)判斷:
// 1. 若Resource<Bitmap>不為空
if (bitmapResource != null) {
result = bitmapDrawableResourceTranscoder.transcode(bitmapResource);
// 則需要再做一次轉(zhuǎn)碼:將Bitmap轉(zhuǎn)換成Drawable對象
// 因?yàn)橐WC靜圖和動圖的類型一致性,否則難以處理->>分析32
} else {
// 2. 若Resource<Bitmap>為空(說明此時(shí)加載的是GIF圖)
// 那么直接調(diào)用getGifResource()方法將圖片取出
// 因?yàn)镚lide用于加載GIF圖片是使用的GifDrawable這個(gè)類,它本身就是一個(gè)Drawable對象
result = gifBitmap.getGifResource();
}
return (Resource<GlideDrawable>) result;
}
...
}
<-- 分析32:bitmapDrawableResourceTranscoder.transcode(bitmapResource)-->
// 作用:再做一次轉(zhuǎn)碼:將Bitmap轉(zhuǎn)換成Drawable對象
public class GlideBitmapDrawableTranscoder implements ResourceTranscoder<Bitmap, GlideBitmapDrawable> {
...
@Override
public Resource<GlideBitmapDrawable> transcode(Resource<Bitmap> toTranscode) {
GlideBitmapDrawable drawable = new GlideBitmapDrawable(resources, toTranscode.get());
// 創(chuàng)建GlideBitmapDrawable對象,并把Bitmap封裝到里面
return new GlideBitmapDrawableResource(drawable, bitmapPool);
// 對GlideBitmapDrawable再進(jìn)行一次封裝,返回Resource<GlideBitmapDrawable>對象
}
}
- 此時(shí),無論是靜圖的
Resource<GlideBitmapDrawable>對象,還是動圖的Resource<GifDrawable>對象,它們都屬于父類Resource<GlideDrawable>對象 - 因此
transcode()返回的是Resource<GlideDrawable>對象,即轉(zhuǎn)換過后的Resource<Z>
所以,分析15DecodeJob的decodeFromSource()中,得到的Resource<Z>對象 是 Resource<GlideDrawable>對象
步驟4:在主線程顯示圖片
繼續(xù)向上返回,最終返回到 EngineRunnable 的 run() 中(分析12)
重新貼出這部分代碼
<--分析12:EngineRunnable的run() -->
@Override
public void run() {
try {
resource = decode();
// 最終得到了Resource<GlideDrawable>對象
// 接下來的工作:將該圖片顯示出來
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception decoding", e);
}
exception = e;
}
if (isCancelled) {
if (resource != null) {
resource.recycle();
}
return;
}
if (resource == null) {
onLoadFailed(exception);
} else {
onLoadComplete(resource);
// 表示圖片加載已經(jīng)完成 ->>分析33
}
}
<-- 分析33: onLoadComplete(resource) -->
private void onLoadComplete(Resource resource) {
manager.onResourceReady(resource);
// 該manager即EngineJob對象
// 實(shí)際上調(diào)用的是EngineJob的onResourceReady() - >>分析34
}
<-- 分析34:EngineJob的onResourceReady() : -->
class EngineJob implements EngineRunnable.EngineRunnableManager {
...
private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
// 創(chuàng)建線程,并綁定主線程的Looper
private final List<ResourceCallback> cbs = new ArrayList<ResourceCallback>();
@Override
public void onResourceReady(final Resource<?> resource) {
this.resource = resource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
// 使用Handler發(fā)出一條 MSG_COMPLETE 消息
// 那么在MainThreadCallback的handleMessage()方法中就會收到這條消息 ->>分析35
// 從此處開始,所有邏輯又回到主線程中進(jìn)行了,即更新UI
}
<-- 分析35:MainThreadCallback的handleMessage()-->
private static class MainThreadCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message message) {
if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) {
EngineJob job = (EngineJob) message.obj;
if (MSG_COMPLETE == message.what) {
job.handleResultOnMainThread();
// 調(diào)用 EngineJob的handleResultOnMainThread() ->>分析36
} else {
job.handleExceptionOnMainThread();
}
return true;
}
return false;
}
}
...
}
<-- 分析36:handleResultOnMainThread() -->
private void handleResultOnMainThread() {
// 通過循環(huán),調(diào)用了所有ResourceCallback的onResourceReady()
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource);
// ResourceCallback 是在addCallback()方法當(dāng)中添加的->>分析37
}
}
engineResource.release();
}
<-- 分析37:addCallback() -->
//
public void addCallback(ResourceCallback cb) {
Util.assertMainThread();
if (hasResource) {
cb.onResourceReady(engineResource);
// 會向cbs集合中去添加ResourceCallback
} else if (hasException) {
cb.onException(exception);
} else {
cbs.add(cb);
}
}
// 而addCallback()是在分析11:Engine的load()中調(diào)用的:
<-- 上面的分析11:Engine的load() -->
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
...
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder, Priority priority,
boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
engineJob.addCallback(cb);
// 調(diào)用addCallback()注冊了一個(gè)ResourceCallback
// 上述參數(shù)cb是load()傳入的的最后一個(gè)參數(shù)
// 而load()是在GenericRequest的onSizeReady()調(diào)用的->>回到分析9(下面重新貼多了一次)
return new LoadStatus(cb, engineJob);
}
...
}
<-- 上面的分析9:onSizeReady() -->
public void onSizeReady(int width, int height) {
...
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
// load()最后一個(gè)參數(shù)是this
// 所以,ResourceCallback類型參數(shù)cb是this
// 而GenericRequest本身實(shí)現(xiàn)了ResourceCallback接口
// 因此,EngineJob的回調(diào) = cb.onResourceReady(engineResource) = 最終回調(diào)GenericRequest的onResourceReady() -->>分析6
}
}
<-- 分析38:GenericRequest的onResourceReady() -->
// onResourceReady()存在兩個(gè)方法重載
// 重載1
public void onResourceReady(Resource<?> resource) {
Object received = resource.get();
// 獲取封裝的圖片對象(GlideBitmapDrawable對象 或 GifDrawable對象
onResourceReady(resource, (R) received);
// 然后將該獲得的圖片對象傳入到了onResourceReady()的重載方法中 ->>看重載2
}
// 重載2
private void onResourceReady(Resource<?> resource, R result) {
...
target.onResourceReady(result, animation);
// Target是在第3步into()的最后1行調(diào)用glide.buildImageViewTarget()方法來構(gòu)建出的Target:GlideDrawableImageViewTarget對象
// ->>分析39
}
<-- 分析39:GlideDrawableImageViewTarget.onResourceReady -->
public class GlideDrawableImageViewTarget extends ImageViewTarget<GlideDrawable> {
@Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) {
if (!resource.isAnimated()) {
float viewRatio = view.getWidth() / (float) view.getHeight();
float drawableRatio = resource.getIntrinsicWidth() / (float) resource.getIntrinsicHeight();
if (Math.abs(viewRatio - 1f) <= SQUARE_RATIO_MARGIN
&& Math.abs(drawableRatio - 1f) <= SQUARE_RATIO_MARGIN) {
resource = new SquaringDrawable(resource, view.getWidth());
}
}
super.onResourceReady(resource, animation);
// 若是靜態(tài)圖片,就調(diào)用父類的.onResourceReady() 將GlideDrawable顯示到ImageView上
// GlideDrawableImageViewTarget的父類是ImageViewTarget ->>分析40
this.resource = resource;
resource.setLoopCount(maxLoopCount);
resource.start();
// 如果是GIF圖片,就調(diào)用resource.start()方法開始播放圖片
}
@Override
protected void setResource(GlideDrawable resource) {
view.setImageDrawable(resource);
}
...
}
<-- 分析40:ImageViewTarget.onResourceReady() -->
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter {
...
@Override
public void onResourceReady(Z resource, GlideAnimation<? super Z> glideAnimation) {
if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
setResource(resource);
// 繼續(xù)往下看
}
}
protected abstract void setResource(Z resource);
// setResource()是一個(gè)抽象方法
// 需要在子類具體實(shí)現(xiàn):請回看上面分析39子類GlideDrawableImageViewTarget類重寫的setResource():調(diào)用view.setImageDrawable(),而這個(gè)view就是ImageView
// 即setResource()的具體實(shí)現(xiàn)是調(diào)用ImageView的setImageDrawable() 并 傳入圖片,于是就實(shí)現(xiàn)了圖片顯示。
}
終于,靜圖 / Gif圖 成功顯示出來
總結(jié)

至此,Glide的基本功能 圖片加載的全功能 解析完畢。
5. 總結(jié)
一圖總結(jié)Glide的基本功能 圖片加載的全過程

下面我將繼續(xù)對 Glide 的其他功能進(jìn)行源碼分析 ,有興趣可以繼續(xù)關(guān)注Carson_Ho的Android開源系列文章。Carson帶你學(xué)Android開源庫系列文章:
Carson帶你學(xué)Android:主流開源圖片加載庫對比(UIL、Picasso、Glide、Fresco)
Carson帶你學(xué)Android:主流開源網(wǎng)絡(luò)請求庫對比(Volley、OkHttp、Retrofit)
Carson帶你學(xué)Android:網(wǎng)絡(luò)請求庫Retrofit使用教程
Carson帶你學(xué)Android:網(wǎng)絡(luò)請求庫Retrofit源碼分析
Carson帶你學(xué)Android:圖片加載庫Glide使用教程
Carson帶你學(xué)Android:圖片加載庫Glide源碼分析
Carson帶你學(xué)Android:V-Layout,淘寶、天貓都在用的UI框架,趕緊用起來吧!
歡迎關(guān)注Carson_Ho的簡書
不定期分享關(guān)于安卓開發(fā)的干貨,追求短、平、快,但卻不缺深度。


