12 Glide 源码分析执行流程

项目地址:https://github.com/bumptech/glide
官方文档:http://bumptech.github.io/glide/
中文文档:https://muyangmin.github.io/glide-docs-cn/
原文链接:https://blog.csdn.net/guolin_blog/article/details/53939176
·
文章目录:
Glide 快速入门
Glide 源码分析执行流程
Glide 缓存机制

在多数情况下,我们想要在界面上加载并展示一张图片只需要一行代码就能实现,如下所示:

1
Glide.with(this).load(url).into(imageView);

虽说只有这简简单单的一行代码,但大家可能不知道的是,Glide 在背后帮我们默默执行了成吨的工作。

我们在平时使用 Glide 的时候格外地简单和方便,但是知其然也要知其所以然。那么今天我们就来解析一下 Glide 的源码,看看它在这些简单用法的背后,到底执行了多么复杂的工作。

with()

with() 方法是 Glide 类中的一组静态方法,它有好几个方法重载,我们来看一下 Glide 类中所有 with() 方法的方法重载:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Glide {
// ...
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
public static RequestManager with(FragmentActivity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static RequestManager with(android.app.Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
public static RequestManager with(Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
}

可以看到,with() 方法的重载种类非常多,既可以传入 Activity,也可以传入 Fragment 或者是 Context。每一个 with() 方法重载的代码都非常简单,都是先调用 RequestManagerRetriever 的静态 get() 方法得到一个 RequestManagerRetriever 对象,这个静态 get() 方法就是一个单例实现,没什么需要解释的。然后再调用 RequestManagerRetriever 的实例 get() 方法,去获取 RequestManager 对象。

而 RequestManagerRetriever 的实例 get() 方法中的逻辑是什么样的呢?我们一起来看一看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
public class RequestManagerRetriever implements Handler.Callback {
private static final RequestManagerRetriever INSTANCE = new RequestManagerRetriever();
private volatile RequestManager applicationManager;
...
/**
* Retrieves and returns the RequestManagerRetriever singleton.
*/
public static RequestManagerRetriever get() {
return INSTANCE;
}
private RequestManager getApplicationManager(Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
// Normally pause/resume is taken care of by the fragment we add to the fragment or activity.
// However, in this case since the manager attached to the application will not receive lifecycle
// events, we must force the manager to start resumed using ApplicationLifecycle.
applicationManager = new RequestManager(context.getApplicationContext(),
new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
}
}
}
return applicationManager;
}
public RequestManager get(Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
public RequestManager get(FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm);
}
}
public RequestManager get(Fragment fragment) {
if (fragment.getActivity() == null) {
throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
}
if (Util.isOnBackgroundThread()) {
return get(fragment.getActivity().getApplicationContext());
} else {
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getActivity(), fm);
}
}
@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);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm);
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private static void assertNotDestroyed(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
throw new IllegalArgumentException("You cannot start a load for a destroyed activity");
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public RequestManager get(android.app.Fragment fragment) {
if (fragment.getActivity() == null) {
throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
}
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return get(fragment.getActivity().getApplicationContext());
} else {
android.app.FragmentManager fm = fragment.getChildFragmentManager();
return fragmentGet(fragment.getActivity(), fm);
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
RequestManagerFragment current = getRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm) {
SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
pendingSupportRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
RequestManager supportFragmentGet(Context context, FragmentManager fm) {
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
...
}

上述代码虽然看上去逻辑有点复杂,但是将它们梳理清楚后还是很简单的。RequestManagerRetriever 类中看似有很多个 get() 方法的重载,什么 Context 参数,Activity 参数,Fragment 参数等等,实际上只有两种情况而已,即传入 Application 类型的参数,和传入非 Application 类型的参数。

我们先来看传入 Application 参数的情况。如果在 Glide.with() 方法中传入的是一个 Application 对象,那么这里就会调用带有 Context 参数的 get() 方法重载,然后会在第 44 行调用 getApplicationManager() 方法来获取一个 RequestManager 对象。其实这是最简单的一种情况,因为 Application 对象的生命周期即应用程序的生命周期,因此 Glide 并不需要做什么特殊的处理,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话, Glide 的加载也会同时终止。

接下来我们看传入非 Application 参数的情况。不管你在 Glide.with() 方法中传入的是 Activity、FragmentActivity、v4 包下的 Fragment、还是 app 包下的 Fragment,最终的流程都是一样的,那就是会向当前的 Activity 当中添加一个隐藏的 Fragment。具体添加的逻辑是在上述代码的第 117 行和第 141 行,分别对应的 app 包和 v4 包下的两种 Fragment 的情况。那么这里为什么要添加一个隐藏的 Fragment 呢?因为 Glide 需要知道加载的生命周期。很简单的一个道理,如果你在某个 Activity 上正在加载着一张图片,结果图片还没加载出来, Activity 就被用户关掉了,那么图片还应该继续加载吗?当然不应该。可是 Glide 并没有办法知道 Activity 的生命周期,于是 Glide 就使用了添加隐藏 Fragment 的这种小技巧,因为 Fragment 的生命周期和 Activity 是同步的,如果 Activity 被销毁了,Fragment 是可以监听到的,这样 Glide 就可以捕获这个事件并停止图片加载了。

这里额外再提一句,从第 48 行代码可以看出,如果我们是在非主线程当中使用的 Glide,那么不管你是传入的 Activity 还是 Fragment,都会被强制当成 Application 来处理。不过其实这就属于是在分析代码的细节了,本篇文章我们将会把目光主要放在 Glide 的主线工作流程上面,后面不会过多去分析这些细节方面的内容。

总体来说,第一个 with() 方法的源码还是比较好理解的。其实就是为了得到一个 RequestManager 对象而已,然后 Glide 会根据我们传入 with() 方法的参数来确定图片加载的生命周期,并没有什么特别复杂的逻辑。不过复杂的逻辑还在后面等着我们呢,接下来我们开始分析第二步,load() 方法。

load()

由于 with() 方法返回的是一个 RequestManager 对象,那么很容易就能想到,load() 方法是在 RequestManager 类当中的,所以说我们首先要看的就是 RequestManager 这个类。不过在上一篇文章中我们学过,Glide 是支持图片 URL 字符串、图片本地路径等等加载形式的,因此 RequestManager 中也有很多个 load() 方法的重载。但是这里我们不可能把每个 load() 方法的重载都看一遍,因此我们就只选其中一个加载图片 URL 字符串的 load() 方法来进行研究。

RequestManager 类的简化代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class RequestManager implements LifecycleListener {
...
/**
* Returns a request builder to load the given {@link String}.
* signature.
*
* @see #fromString()
* @see #load(Object)
*
* @param string A file path, or a uri or url handled by {@link com.bumptech.glide.load.model.UriLoader}.
*/
public DrawableTypeRequest<String> load(String string) {
return (DrawableTypeRequest<String>) fromString().load(string);
}
/**
* Returns a request builder that loads data from {@link String}s using an empty signature.
*
* <p>
* Note - this method caches data using only the given String as the cache key. If the data is a Uri outside of
* your control, or you otherwise expect the data represented by the given String to change without the String
* identifier changing, Consider using
* {@link GenericRequestBuilder#signature(Key)} to mixin a signature
* you create that identifies the data currently at the given String that will invalidate the cache if that data
* changes. Alternatively, using {@link DiskCacheStrategy#NONE} and/or
* {@link DrawableRequestBuilder#skipMemoryCache(boolean)} may be appropriate.
* </p>
*
* @see #from(Class)
* @see #load(String)
*/
public DrawableTypeRequest<String> fromString() {
return loadGeneric(String.class);
}
private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
Glide.buildFileDescriptorModelLoader(modelClass, context);
if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for"
+ " which there is a registered ModelLoader, if you are using a custom model, you must first call"
+ " Glide#register with a ModelLoaderFactory for your custom model class");
}
return optionsApplier.apply(
new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
glide, requestTracker, lifecycle, optionsApplier));
}
...
}

RequestManager 类的代码是非常多的,但是经过我这样简化之后,看上去就比较清爽了。在我们只探究加载图片 URL 字符串这一个 load() 方法的情况下,那么比较重要的方法就只剩下上述代码中的这三个方法。

那么我们先来看 load() 方法,这个方法中的逻辑是非常简单的,只有一行代码,就是先调用了 fromString() 方法,再调用 load() 方法,然后把传入的图片 URL 地址传进去。而 fromString() 方法也极为简单,就是调用了 loadGeneric() 方法,并且指定参数为 String.class,因为 load() 方法传入的是一个字符串参数。那么看上去,好像主要的工作都是在 loadGeneric() 方法中进行的了。

其实 loadGeneric() 方法也没几行代码,这里分别调用了 Glide.buildStreamModelLoader() 方法和 Glide.buildFileDescriptorModelLoader() 方法来获得 ModelLoader 对象。ModelLoader 对象是用于加载图片的,而我们给 load() 方法传入不同类型的参数,这里也会得到不同的 ModelLoader 对象。不过 buildStreamModelLoader() 方法内部的逻辑还是蛮复杂的,这里就不展开介绍了,要不然篇幅实在收不住,感兴趣的话你可以自己研究。由于我们刚才传入的参数是 String.class,因此最终得到的是 StreamStringLoader 对象,它是实现了 ModelLoader 接口的。

最后我们可以看到,loadGeneric() 方法是要返回一个 DrawableTypeRequest 对象的,因此在 loadGeneric() 方法的最后又去 new 了一个 DrawableTypeRequest 对象,然后把刚才获得的 ModelLoader 对象,还有一大堆杂七杂八的东西都传了进去。具体每个参数的含义和作用就不解释了,我们只看主线流程。

那么这个 DrawableTypeRequest 的作用是什么呢?我们来看下它的源码,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
private final ModelLoader<ModelType, InputStream> streamModelLoader;
private final ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader;
private final RequestManager.OptionsApplier optionsApplier;
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 (streamModelLoader == null && fileDescriptorModelLoader == null) {
return null;
}
if (transcoder == null) {
transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
}
DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
resourceClass);
ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
fileDescriptorModelLoader);
return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
}
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);
this.streamModelLoader = streamModelLoader;
this.fileDescriptorModelLoader = fileDescriptorModelLoader;
this.optionsApplier = optionsApplier;
}
/**
* Attempts to always load the resource as a {@link android.graphics.Bitmap}, even if it could actually be animated.
*
* @return A new request builder for loading a {@link android.graphics.Bitmap}
*/
public BitmapTypeRequest<ModelType> asBitmap() {
return optionsApplier.apply(new BitmapTypeRequest<ModelType>(this, streamModelLoader,
fileDescriptorModelLoader, optionsApplier));
}
/**
* Attempts to always load the resource as a {@link com.bumptech.glide.load.resource.gif.GifDrawable}.
* <p>
* If the underlying data is not a GIF, this will fail. As a result, this should only be used if the model
* represents an animated GIF and the caller wants to interact with the GIfDrawable directly. Normally using
* just an {@link DrawableTypeRequest} is sufficient because it will determine whether or
* not the given data represents an animated GIF and return the appropriate animated or not animated
* {@link android.graphics.drawable.Drawable} automatically.
* </p>
*
* @return A new request builder for loading a {@link com.bumptech.glide.load.resource.gif.GifDrawable}.
*/
public GifTypeRequest<ModelType> asGif() {
return optionsApplier.apply(new GifTypeRequest<ModelType>(this, streamModelLoader, optionsApplier));
}
...
}

这个类中的代码本身就不多,我只是稍微做了一点简化。可以看到,最主要的就是它提供了 asBitmap() 和 asGif() 这两个方法。这两个方法分别是用于强制指定加载静态图片和动态图片。而从源码中可以看出,它们分别又创建了一个 BitmapTypeRequest 和 GifTypeRequest,如果没有进行强制指定的话,那默认就是使用 DrawableTypeRequest。

好的,那么我们再回到 RequestManager 的 load() 方法中。刚才已经分析过了,fromString() 方法会返回一个 DrawableTypeRequest 对象,接下来会调用这个对象的 load() 方法,把图片的 URL 地址传进去。但是我们刚才看到了,DrawableTypeRequest 中并没有 load() 方法,那么很容易就能猜想到,load() 方法是在父类当中的。

DrawableTypeRequest 的父类是 DrawableRequestBuilder,我们来看下这个类的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
public class DrawableRequestBuilder<ModelType>
extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
implements BitmapOptions, DrawableOptions {
DrawableRequestBuilder(Context context, Class<ModelType> modelClass,
LoadProvider<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable> loadProvider, Glide glide,
RequestTracker requestTracker, Lifecycle lifecycle) {
super(context, modelClass, loadProvider, GlideDrawable.class, glide, requestTracker, lifecycle);
// Default to animating.
crossFade();
}
public DrawableRequestBuilder<ModelType> thumbnail(
DrawableRequestBuilder<?> thumbnailRequest) {
super.thumbnail(thumbnailRequest);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> thumbnail(
GenericRequestBuilder<?, ?, ?, GlideDrawable> thumbnailRequest) {
super.thumbnail(thumbnailRequest);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> thumbnail(float sizeMultiplier) {
super.thumbnail(sizeMultiplier);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> sizeMultiplier(float sizeMultiplier) {
super.sizeMultiplier(sizeMultiplier);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> decoder(ResourceDecoder<ImageVideoWrapper, GifBitmapWrapper> decoder) {
super.decoder(decoder);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> cacheDecoder(ResourceDecoder<File, GifBitmapWrapper> cacheDecoder) {
super.cacheDecoder(cacheDecoder);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> encoder(ResourceEncoder<GifBitmapWrapper> encoder) {
super.encoder(encoder);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> priority(Priority priority) {
super.priority(priority);
return this;
}
public DrawableRequestBuilder<ModelType> transform(BitmapTransformation... transformations) {
return bitmapTransform(transformations);
}
public DrawableRequestBuilder<ModelType> centerCrop() {
return transform(glide.getDrawableCenterCrop());
}
public DrawableRequestBuilder<ModelType> fitCenter() {
return transform(glide.getDrawableFitCenter());
}
public DrawableRequestBuilder<ModelType> bitmapTransform(Transformation<Bitmap>... bitmapTransformations) {
GifBitmapWrapperTransformation[] transformations =
new GifBitmapWrapperTransformation[bitmapTransformations.length];
for (int i = 0; i < bitmapTransformations.length; i++) {
transformations[i] = new GifBitmapWrapperTransformation(glide.getBitmapPool(), bitmapTransformations[i]);
}
return transform(transformations);
}
@Override
public DrawableRequestBuilder<ModelType> transform(Transformation<GifBitmapWrapper>... transformation) {
super.transform(transformation);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> transcoder(
ResourceTranscoder<GifBitmapWrapper, GlideDrawable> transcoder) {
super.transcoder(transcoder);
return this;
}
public final DrawableRequestBuilder<ModelType> crossFade() {
super.animate(new DrawableCrossFadeFactory<GlideDrawable>());
return this;
}
public DrawableRequestBuilder<ModelType> crossFade(int duration) {
super.animate(new DrawableCrossFadeFactory<GlideDrawable>(duration));
return this;
}
public DrawableRequestBuilder<ModelType> crossFade(int animationId, int duration) {
super.animate(new DrawableCrossFadeFactory<GlideDrawable>(context, animationId,
duration));
return this;
}
@Override
public DrawableRequestBuilder<ModelType> dontAnimate() {
super.dontAnimate();
return this;
}
@Override
public DrawableRequestBuilder<ModelType> animate(ViewPropertyAnimation.Animator animator) {
super.animate(animator);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> animate(int animationId) {
super.animate(animationId);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> placeholder(int resourceId) {
super.placeholder(resourceId);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> placeholder(Drawable drawable) {
super.placeholder(drawable);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> fallback(Drawable drawable) {
super.fallback(drawable);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> fallback(int resourceId) {
super.fallback(resourceId);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> error(int resourceId) {
super.error(resourceId);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> error(Drawable drawable) {
super.error(drawable);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> listener(
RequestListener<? super ModelType, GlideDrawable> requestListener) {
super.listener(requestListener);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> diskCacheStrategy(DiskCacheStrategy strategy) {
super.diskCacheStrategy(strategy);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> skipMemoryCache(boolean skip) {
super.skipMemoryCache(skip);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> override(int width, int height) {
super.override(width, height);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> sourceEncoder(Encoder<ImageVideoWrapper> sourceEncoder) {
super.sourceEncoder(sourceEncoder);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> dontTransform() {
super.dontTransform();
return this;
}
@Override
public DrawableRequestBuilder<ModelType> signature(Key signature) {
super.signature(signature);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> load(ModelType model) {
super.load(model);
return this;
}
@Override
public DrawableRequestBuilder<ModelType> clone() {
return (DrawableRequestBuilder<ModelType>) super.clone();
}
@Override
public Target<GlideDrawable> into(ImageView view) {
return super.into(view);
}
@Override
void applyFitCenter() {
fitCenter();
}
@Override
void applyCenterCrop() {
centerCrop();
}
}

DrawableRequestBuilder 中有很多个方法,这些方法其实就是 Glide 绝大多数的 API 了。里面有不少我们在上篇文章中已经用过了,比如说 placeholder() 方法、error() 方法、diskCacheStrategy() 方法、override() 方法等。当然还有很多暂时还没用到的 API,我们会在后面的文章当中学习。

到这里,第二步 load() 方法也就分析结束了。为什么呢?因为你会发现 DrawableRequestBuilder 类中有一个 into() 方法(上述代码第 220 行),也就是说,最终 load() 方法返回的其实就是一个 DrawableTypeRequest 对象。那么接下来我们就要进行第三步了,分析 into() 方法中的逻辑。

into()

如果说前面两步都是在准备开胃小菜的话,那么现在终于要进入主菜了,因为 into() 方法也是整个 Glide 图片加载流程中逻辑最复杂的地方。

不过从刚才的代码来看,into() 方法中并没有任何逻辑,只有一句 super.into(view)。那么很显然,into() 方法的具体逻辑都是在 DrawableRequestBuilder 的父类当中了。

DrawableRequestBuilder 的父类是 GenericRequestBuilder,我们来看一下 GenericRequestBuilder 类中的 into() 方法,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public Target<TranscodeType> into(ImageView view) {
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));
}

这里前面一大堆的判断逻辑我们都可以先不用管,等到后面文章讲 transform 的时候会再进行解释,现在我们只需要关注最后一行代码。最后一行代码先是调用了 glide.buildImageViewTarget() 方法,这个方法会构建出一个 Target 对象,Target 对象则是用来最终展示图片用的,如果我们跟进去的话会看到如下代码:

1
2
3
<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
}

这里其实又是调用了 ImageViewTargetFactory 的 buildTarget() 方法,我们继续跟进去,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ImageViewTargetFactory {
@SuppressWarnings("unchecked")
public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
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)");
}
}
}

可以看到,在 buildTarget() 方法中会根据传入的 class 参数来构建不同的 Target 对象。那如果你要分析这个 class 参数是从哪儿传过来的,这可有得你分析了,简单起见我直接帮大家梳理清楚。这个 class 参数其实基本上只有两种情况,如果你在使用 Glide 加载图片的时候调用了 asBitmap() 方法,那么这里就会构建出 BitmapImageViewTarget 对象,否则的话构建的都是 GlideDrawableImageViewTarget 对象。至于上述代码中的 DrawableImageViewTarget 对象,这个通常都是用不到的,我们可以暂时不用管它。

也就是说,通过 glide.buildImageViewTarget() 方法,我们构建出了一个 GlideDrawableImageViewTarget 对象。那现在回到刚才 into() 方法的最后一行,可以看到,这里又将这个参数传入到了 GenericRequestBuilder 另一个接收 Target 对象的 into() 方法当中了。我们来看一下这个 into() 方法的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public <Y extends Target<TranscodeType>> Y into(Y target) {
Util.assertMainThread();
if (target == null) {
throw new IllegalArgumentException("You must pass in a non null Target");
}
if (!isModelSet) {
throw new IllegalArgumentException("You must first set a model (try #load())");
}
Request previous = target.getRequest();
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
requestTracker.runRequest(request);
return target;
}

这里我们还是只抓核心代码,其实只有两行是最关键的,第 15 行调用 buildRequest() 方法构建出了一个 Request 对象,还有第 18 行来执行这个 Request。

Request 是用来发出加载图片请求的,它是 Glide 中非常关键的一个组件。我们先来看 buildRequest() 方法是如何构建 Request 对象的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
private Request buildRequest(Target<TranscodeType> target) {
if (priority == null) {
priority = Priority.NORMAL;
}
return buildRequestRecursive(target, null);
}
private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
if (thumbnailRequestBuilder != null) {
if (isThumbnailBuilt) {
throw new IllegalStateException("You cannot use a request as both the main request and a thumbnail, "
+ "consider using clone() on the request(s) passed to thumbnail()");
}
// Recursive case: contains a potentially recursive thumbnail request builder.
if (thumbnailRequestBuilder.animationFactory.equals(NoAnimation.getFactory())) {
thumbnailRequestBuilder.animationFactory = animationFactory;
}
if (thumbnailRequestBuilder.priority == null) {
thumbnailRequestBuilder.priority = getThumbnailPriority();
}
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !Util.isValidDimensions(thumbnailRequestBuilder.overrideWidth,
thumbnailRequestBuilder.overrideHeight)) {
thumbnailRequestBuilder.override(overrideWidth, overrideHeight);
}
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
// Guard against infinite recursion.
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
Request thumbRequest = thumbnailRequestBuilder.buildRequestRecursive(target, coordinator);
isThumbnailBuilt = false;
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {
// Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
Request thumbnailRequest = obtainRequest(target, thumbSizeMultiplier, getThumbnailPriority(), coordinator);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
// Base case: no thumbnail.
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
}
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);
}

可以看到,buildRequest() 方法的内部其实又调用了 buildRequestRecursive() 方法,而 buildRequestRecursive() 方法中的代码虽然有点长,但是其中 90% 的代码都是在处理缩略图的。如果我们只追主线流程的话,那么只需要看第 47 行代码就可以了。这里调用了 obtainRequest() 方法来获取一个 Request 对象,而 obtainRequest() 方法中又去调用了 GenericRequest 的 obtain() 方法。注意这个 obtain() 方法需要传入非常多的参数,而其中很多的参数我们都是比较熟悉的,像什么 placeholderId、errorPlaceholder、diskCacheStrategy 等等。因此,我们就有理由猜测,刚才在 load()方法中调用的所有 API,其实都是在这里组装到 Request 对象当中的。那么我们进入到这个 GenericRequest 的 obtain() 方法瞧一瞧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,
ResourceCallback {
...
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>();
}
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;
}
...
}

可以看到,这里在第 33 行去 new 了一个 GenericRequest 对象,并在最后一行返回,也就是说,obtain() 方法实际上获得的就是一个 GenericRequest 对象。另外这里又在第 35 行调用了 GenericRequest 的 init(),里面主要就是一些赋值的代码,将传入的这些参数赋值到 GenericRequest 的成员变量当中,我们就不再跟进去看了。

好,那现在解决了构建 Request 对象的问题,接下来我们看一下这个 Request 对象又是怎么执行的。回到刚才的 into() 方法,你会发现在第 18 行调用了 requestTracker.runRequest() 方法来去执行这个 Request,那么我们跟进去瞧一瞧,如下所示:

1
2
3
4
5
6
7
8
9
10
11
/**
* Starts tracking the given request.
*/
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}

这里有一个简单的逻辑判断,就是先判断 Glide 当前是不是处理暂停状态,如果不是暂停状态就调用 Request 的 begin() 方法来执行 Request,否则的话就先将 Request 添加到待执行队列里面,等暂停状态解除了之后再执行。

暂停请求的功能仍然不是这篇文章所关心的,这里就直接忽略了,我们重点来看这个 begin() 方法。由于当前的 Request 对象是一个 GenericRequest,因此这里就需要看 GenericRequest 中的 begin() 方法了,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}

这里我们来注意几个细节,首先如果 model 等于 null,model 也就是我们在第二步 load() 方法中传入的图片 URL 地址,这个时候会调用 onException() 方法。如果你跟到 onException() 方法里面去看看,你会发现它最终会调用到一个 setErrorPlaceholder() 当中,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
private void setErrorPlaceholder(Exception e) {
if (!canNotifyStatusChanged()) {
return;
}
Drawable error = model == null ? getFallbackDrawable() : null;
if (error == null) {
error = getErrorDrawable();
}
if (error == null) {
error = getPlaceholderDrawable();
}
target.onLoadFailed(e, error);
}

这个方法中会先去获取一个 error 的占位图,如果获取不到的话会再去获取一个 loading 占位图,然后调用 target.onLoadFailed() 方法并将占位图传入。那么 onLoadFailed() 方法中做了什么呢?我们看一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter {
...
@Override
public void onLoadStarted(Drawable placeholder) {
view.setImageDrawable(placeholder);
}
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
view.setImageDrawable(errorDrawable);
}
...
}

很简单,其实就是将这张 error 占位图显示到 ImageView 上而已,因为现在出现了异常,没办法展示正常的图片了。而如果你仔细看下刚才 begin() 方法的第 15 行,你会发现它又调用了一个 target.onLoadStarted() 方法,并传入了一个 loading 占位图,在也就说,在图片请求开始之前,会先使用这张占位图代替最终的图片显示。这也是我们在上一篇文章中学过的 placeholder() 和 error() 这两个占位图 API 底层的实现原理。

好,那么我们继续回到 begin() 方法。刚才讲了占位图的实现,那么具体的图片加载又是从哪里开始的呢?是在 begin() 方法的第 10 行和第 12 行。这里要分两种情况,一种是你使用了 override() API 为图片指定了一个固定的宽高,一种是没有指定。如果指定了的话,就会执行第 10 行代码,调用 onSizeReady() 方法。如果没指定的话,就会执行第 12 行代码,调用 target.getSize() 方法。这个 target.getSize() 方法的内部会根据 ImageView 的 layout_width 和 layout_height 值做一系列的计算,来算出图片应该的宽高。具体的计算细节我就不带着大家分析了,总之在计算完之后,它也会调用 onSizeReady() 方法。也就是说,不管是哪种情况,最终都会调用到 onSizeReady() 方法,在这里进行下一步操作。那么我们跟到这个方法里面来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
public void onSizeReady(int width, int height) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
width = Math.round(sizeMultiplier * width);
height = Math.round(sizeMultiplier * height);
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadedFromMemoryCache = true;
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
loadedFromMemoryCache = resource != null;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}

从这里开始,真正复杂的地方来了,我们需要慢慢进行分析。先来看一下,在第12行调用了 loadProvider.getModelLoader() 方法,那么我们第一个要搞清楚的就是,这个 loadProvider 是什么?要搞清楚这点,需要先回到第二步的 load() 方法当中。还记得 load() 方法是返回一个 DrawableTypeRequest 对象吗?刚才我们只是分析了 DrawableTypeRequest 当中的 asBitmap() 和 asGif() 方法,并没有仔细看它的构造函数,现在我们重新来看一下 DrawableTypeRequest类的构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
private final ModelLoader<ModelType, InputStream> streamModelLoader;
private final ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader;
private final RequestManager.OptionsApplier optionsApplier;
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 (streamModelLoader == null && fileDescriptorModelLoader == null) {
return null;
}
if (transcoder == null) {
transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
}
DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
resourceClass);
ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
fileDescriptorModelLoader);
return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
}
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);
this.streamModelLoader = streamModelLoader;
this.fileDescriptorModelLoader = fileDescriptorModelLoader;
this.optionsApplier = optionsApplier;
}
...
}

可以看到,这里在第 29 行,也就是构造函数中,调用了一个 buildProvider() 方法,并把 streamModelLoader 和 fileDescriptorModelLoader 等参数传入到这个方法中,这两个 ModelLoader 就是之前在 loadGeneric() 方法中构建出来的。

那么我们再来看一下 buildProvider() 方法里面做了什么,在第 16 行调用了 glide.buildTranscoder() 方法来构建一个 ResourceTranscoder,它是用于对图片进行转码的,由于 ResourceTranscoder 是一个接口,这里实际会构建出一个 GifBitmapWrapperDrawableTranscoder 对象。

接下来在第 18 行调用了 glide.buildDataProvider() 方法来构建一个 DataLoadProvider,它是用于对图片进行编解码的,由于 DataLoadProvider 是一个接口,这里实际会构建出一个 ImageVideoGifDrawableLoadProvider 对象。

然后在第 20 行,new 了一个 ImageVideoModelLoader 的实例,并把之前 loadGeneric() 方法中构建的两个 ModelLoader 封装到了 ImageVideoModelLoader 当中。

最后,在第 22 行,new 出一个 FixedLoadProvider,并把刚才构建的出来的 GifBitmapWrapperDrawableTranscoder、ImageVideoModelLoader、ImageVideoGifDrawableLoadProvider 都封装进去,这个也就是 onSizeReady() 方法中的 loadProvider 了。

好的,那么我们回到 onSizeReady() 方法中,在 onSizeReady() 方法的第 12 行和第 18 行,分别调用了 loadProvider 的 getModelLoader() 方法和 getTranscoder() 方法,那么得到的对象也就是刚才我们分析的 ImageVideoModelLoader 和 GifBitmapWrapperDrawableTranscoder 了。而在第 13 行,又调用了 ImageVideoModelLoader 的 getResourceFetcher() 方法,这里我们又需要跟进去瞧一瞧了,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class ImageVideoModelLoader<A> implements ModelLoader<A, ImageVideoWrapper> {
private static final String TAG = "IVML";
private final ModelLoader<A, InputStream> streamLoader;
private final ModelLoader<A, ParcelFileDescriptor> fileDescriptorLoader;
public ImageVideoModelLoader(ModelLoader<A, InputStream> streamLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorLoader) {
if (streamLoader == null && fileDescriptorLoader == null) {
throw new NullPointerException("At least one of streamLoader and fileDescriptorLoader must be non null");
}
this.streamLoader = streamLoader;
this.fileDescriptorLoader = fileDescriptorLoader;
}
@Override
public DataFetcher<ImageVideoWrapper> getResourceFetcher(A model, int width, int height) {
DataFetcher<InputStream> streamFetcher = null;
if (streamLoader != null) {
streamFetcher = streamLoader.getResourceFetcher(model, width, height);
}
DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher = null;
if (fileDescriptorLoader != null) {
fileDescriptorFetcher = fileDescriptorLoader.getResourceFetcher(model, width, height);
}
if (streamFetcher != null || fileDescriptorFetcher != null) {
return new ImageVideoFetcher(streamFetcher, fileDescriptorFetcher);
} else {
return null;
}
}
static class ImageVideoFetcher implements DataFetcher<ImageVideoWrapper> {
private final DataFetcher<InputStream> streamFetcher;
private final DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher;
public ImageVideoFetcher(DataFetcher<InputStream> streamFetcher,
DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher) {
this.streamFetcher = streamFetcher;
this.fileDescriptorFetcher = fileDescriptorFetcher;
}
...
}
}

可以看到,在第 20 行会先调用 streamLoader.getResourceFetcher() 方法获取一个 DataFetcher,而这个 streamLoader 其实就是我们在 loadGeneric() 方法中构建出的 StreamStringLoader,调用它的 getResourceFetcher() 方法会得到一个 HttpUrlFetcher 对象。然后在第 28 行 new 出了一个 ImageVideoFetcher 对象,并把获得的 HttpUrlFetcher 对象传进去。也就是说,ImageVideoModelLoader 的 getResourceFetcher() 方法得到的是一个 ImageVideoFetcher。

那么我们再次回到 onSizeReady() 方法,在 onSizeReady() 方法的第 23 行,这里将刚才获得的 ImageVideoFetcher、GifBitmapWrapperDrawableTranscoder 等等一系列的值一起传入到了 Engine 的 load() 方法当中。接下来我们就要看一看,这个 Engine 的 load() 方法当中,到底做了什么?代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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) {
Util.assertMainThread();
long startTime = LogTime.getLogTime();
final String id = fetcher.getId();
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
transcoder, loadProvider.getSourceEncoder());
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
...
}

load() 方法中的代码虽然有点长,但大多数的代码都是在处理缓存的。关于缓存的内容我们会在下一篇文章当中学习,现在只需要从第 45 行看起就行。这里构建了一个 EngineJob,它的主要作用就是用来开启线程的,为后面的异步加载图片做准备。接下来第 46 行创建了一个 DecodeJob 对象,从名字上来看,它好像是用来对图片进行解码的,但实际上它的任务十分繁重,待会我们就知道了。继续往下看,第 48 行创建了一个 EngineRunnable 对象,并且在 51 行调用了 EngineJob 的 start() 方法来运行 EngineRunnable 对象,这实际上就是让 EngineRunnable 的 run() 方法在子线程当中执行了。那么我们现在就可以去看看 EngineRunnable 的 run() 方法里做了些什么,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
resource = decode();
} 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);
}
}

这个方法中的代码并不多,但我们仍然还是要抓重点。在第 9 行,这里调用了一个 decode() 方法,并且这个方法返回了一个 Resource 对象。看上去所有的逻辑应该都在这个 decode() 方法执行的了,那我们跟进去瞧一瞧:

1
2
3
4
5
6
7
private Resource<?> decode() throws Exception {
if (isDecodingFromCache()) {
return decodeFromCache();
} else {
return decodeFromSource();
}
}

decode() 方法中又分了两种情况,从缓存当中去 decode 图片的话就会执行 decodeFromCache(),否则的话就执行 decodeFromSource()。本篇文章中我们不讨论缓存的情况,那么就直接来看 decodeFromSource() 方法的代码吧,如下所示:

1
2
3
private Resource<?> decodeFromSource() throws Exception {
return decodeJob.decodeFromSource();
}

这里又调用了 DecodeJob 的 decodeFromSource() 方法。刚才已经说了,DecodeJob 的任务十分繁重,我们继续跟进看一看吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class DecodeJob<A, T, Z> {
...
public Resource<Z> decodeFromSource() throws Exception {
Resource<T> decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
}
private Resource<T> decodeSource() throws Exception {
Resource<T> decoded = null;
try {
long startTime = LogTime.getLogTime();
final A data = fetcher.loadData(priority);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Fetched data", startTime);
}
if (isCancelled) {
return null;
}
decoded = decodeFromSourceData(data);
} finally {
fetcher.cleanup();
}
return decoded;
}
...
}

主要的方法就这些,我都帮大家提取出来了。那么我们先来看一下 decodeFromSource() 方法,其实它的工作分为两部,第一步是调用 decodeSource() 方法来获得一个 Resource 对象,第二步是调用 transformEncodeAndTranscode() 方法来处理这个 Resource 对象。

那么我们先来看第一步,decodeSource() 方法中的逻辑也并不复杂,首先在第 14 行调用了 fetcher.loadData() 方法。那么这个 fetcher 是什么呢?其实就是刚才在 onSizeReady() 方法中得到的 ImageVideoFetcher 对象,这里调用它的 loadData() 方法,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Override
public ImageVideoWrapper loadData(Priority priority) throws Exception {
InputStream is = null;
if (streamFetcher != null) {
try {
is = streamFetcher.loadData(priority);
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception fetching input stream, trying ParcelFileDescriptor", e);
}
if (fileDescriptorFetcher == null) {
throw e;
}
}
}
ParcelFileDescriptor fileDescriptor = null;
if (fileDescriptorFetcher != null) {
try {
fileDescriptor = fileDescriptorFetcher.loadData(priority);
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception fetching ParcelFileDescriptor", e);
}
if (is == null) {
throw e;
}
}
}
return new ImageVideoWrapper(is, fileDescriptor);
}

可以看到,在 ImageVideoFetcher 的 loadData() 方法的第 6 行,这里又去调用了 streamFetcher.loadData() 方法,那么这个 streamFetcher 是什么呢?自然就是刚才在组装 ImageVideoFetcher 对象时传进来的 HttpUrlFetcher 了。因此这里又会去调用 HttpUrlFetcher 的 loadData() 方法,那么我们继续跟进去瞧一瞧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class HttpUrlFetcher implements DataFetcher<InputStream> {
...
@Override
public InputStream loadData(Priority priority) throws Exception {
return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
}
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers)
throws IOException {
if (redirects >= MAXIMUM_REDIRECTS) {
throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
} else {
// Comparing the URLs using .equals performs additional network I/O and is generally broken.
// See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new IOException("In re-direct loop");
}
} catch (URISyntaxException e) {
// Do nothing, this is best effort.
}
}
urlConnection = connectionFactory.build(url);
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(2500);
urlConnection.setReadTimeout(2500);
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);
} else if (statusCode / 100 == 3) {
String redirectUrlString = urlConnection.getHeaderField("Location");
if (TextUtils.isEmpty(redirectUrlString)) {
throw new IOException("Received empty or null redirect url");
}
URL redirectUrl = new URL(url, redirectUrlString);
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else {
if (statusCode == -1) {
throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
}
throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
}
}
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;
}
...
}

经过一层一层地跋山涉水,我们终于在这里找到网络通讯的代码了!之前有朋友跟我讲过,说 Glide 的源码实在是太复杂了,甚至连网络请求是在哪里发出去的都找不到。我们也是经过一段一段又一段的代码跟踪,终于把网络请求的代码给找出来了,实在是太不容易了。

不过也别高兴得太早,现在离最终分析完还早着呢。可以看到, loadData() 方法只是返回了一个 InputStream,服务器返回的数据连读都还没开始读呢。所以我们还是要静下心来继续分析,回到刚才 ImageVideoFetcher 的 loadData() 方法中,在这个方法的最后一行,创建了一个 ImageVideoWrapper 对象,并把刚才得到的 InputStream 作为参数传了进去。

然后我们回到再上一层,也就是 DecodeJob 的 decodeSource() 方法当中,在得到了这个 ImageVideoWrapper 对象之后,紧接着又将这个对象传入到了 decodeFromSourceData() 当中,来去解码这个对象。decodeFromSourceData() 方法的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
private Resource<T> decodeFromSourceData(A data) throws IOException {
final Resource<T> decoded;
if (diskCacheStrategy.cacheSource()) {
decoded = cacheAndDecodeSourceData(data);
} else {
long startTime = LogTime.getLogTime();
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded from source", startTime);
}
}
return decoded;
}

可以看到,这里在第 7 行调用了 loadProvider.getSourceDecoder().decode() 方法来进行解码。loadProvider 就是刚才在 onSizeReady() 方法中得到的 FixedLoadProvider,而 getSourceDecoder() 得到的则是一个 GifBitmapWrapperResourceDecoder 对象,也就是要调用这个对象的 decode() 方法来对图片进行解码。那么我们来看下 GifBitmapWrapperResourceDecoder 的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class GifBitmapWrapperResourceDecoder implements ResourceDecoder<ImageVideoWrapper, GifBitmapWrapper> {
...
@SuppressWarnings("resource")
// @see ResourceDecoder.decode
@Override
public Resource<GifBitmapWrapper> decode(ImageVideoWrapper source, int width, int height) throws IOException {
ByteArrayPool pool = ByteArrayPool.get();
byte[] tempBytes = pool.getBytes();
GifBitmapWrapper wrapper = null;
try {
wrapper = decode(source, width, height, tempBytes);
} finally {
pool.releaseBytes(tempBytes);
}
return wrapper != null ? new GifBitmapWrapperResource(wrapper) : null;
}
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);
} else {
result = decodeBitmapWrapper(source, width, height);
}
return result;
}
private GifBitmapWrapper decodeStream(ImageVideoWrapper source, int width, int height, byte[] bytes)
throws IOException {
InputStream bis = streamFactory.build(source.getStream(), bytes);
bis.mark(MARK_LIMIT_BYTES);
ImageHeaderParser.ImageType type = parser.parse(bis);
bis.reset();
GifBitmapWrapper result = null;
if (type == ImageHeaderParser.ImageType.GIF) {
result = decodeGifWrapper(bis, width, height);
}
// Decoding the gif may fail even if the type matches.
if (result == null) {
// We can only reset the buffered InputStream, so to start from the beginning of the stream, we need to
// pass in a new source containing the buffered stream rather than the original stream.
ImageVideoWrapper forBitmapDecoder = new ImageVideoWrapper(bis, source.getFileDescriptor());
result = decodeBitmapWrapper(forBitmapDecoder, width, height);
}
return result;
}
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);
}
return result;
}
...
}

首先,在 decode() 方法中,又去调用了另外一个 decode() 方法的重载。然后在第 23 行调用了 decodeStream() 方法,准备从服务器返回的流当中读取数据。decodeStream() 方法中会先从流中读取 2 个字节的数据,来判断这张图是 GIF 图还是普通的静图,如果是 GIF 图就调用 decodeGifWrapper() 方法来进行解码,如果是普通的静图就用调用 decodeBitmapWrapper() 方法来进行解码。这里我们只分析普通静图的实现流程,GIF 图的实现有点过于复杂了,无法在本篇文章当中分析。

然后我们来看一下 decodeBitmapWrapper() 方法,这里在第 52 行调用了 bitmapDecoder.decode() 方法。这个 bitmapDecoder 是一个 ImageVideoBitmapDecoder 对象,那么我们来看一下它的代码,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class ImageVideoBitmapDecoder implements ResourceDecoder<ImageVideoWrapper, Bitmap> {
private final ResourceDecoder<InputStream, Bitmap> streamDecoder;
private final ResourceDecoder<ParcelFileDescriptor, Bitmap> fileDescriptorDecoder;
public ImageVideoBitmapDecoder(ResourceDecoder<InputStream, Bitmap> streamDecoder,
ResourceDecoder<ParcelFileDescriptor, Bitmap> fileDescriptorDecoder) {
this.streamDecoder = streamDecoder;
this.fileDescriptorDecoder = fileDescriptorDecoder;
}
@Override
public Resource<Bitmap> decode(ImageVideoWrapper source, int width, int height) throws IOException {
Resource<Bitmap> result = null;
InputStream is = source.getStream();
if (is != null) {
try {
result = streamDecoder.decode(is, width, height);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Failed to load image from stream, trying FileDescriptor", e);
}
}
}
if (result == null) {
ParcelFileDescriptor fileDescriptor = source.getFileDescriptor();
if (fileDescriptor != null) {
result = fileDescriptorDecoder.decode(fileDescriptor, width, height);
}
}
return result;
}
...
}

代码并不复杂,在第 14 行先调用了 source.getStream() 来获取到服务器返回的 InputStream,然后在第 17 行调用 streamDecoder.decode() 方法进行解码。streamDecode 是一个 StreamBitmapDecoder 对象,那么我们再来看这个类的源码,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class StreamBitmapDecoder implements ResourceDecoder<InputStream, Bitmap> {
...
private final Downsampler downsampler;
private BitmapPool bitmapPool;
private DecodeFormat decodeFormat;
public StreamBitmapDecoder(Downsampler downsampler, BitmapPool bitmapPool, DecodeFormat decodeFormat) {
this.downsampler = downsampler;
this.bitmapPool = bitmapPool;
this.decodeFormat = decodeFormat;
}
@Override
public Resource<Bitmap> decode(InputStream source, int width, int height) {
Bitmap bitmap = downsampler.decode(source, bitmapPool, width, height, decodeFormat);
return BitmapResource.obtain(bitmap, bitmapPool);
}
...
}

可以看到,它的 decode() 方法又去调用了 Downsampler 的 decode() 方法。接下来又到了激动人心的时刻了,Downsampler 的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
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);
try {
if (options.inJustDecodeBounds) {
is.reset();
}
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.ERROR)) {
Log.e(TAG, "Exception loading inDecodeBounds=" + options.inJustDecodeBounds
+ " sample=" + options.inSampleSize, e);
}
}
return result;
}
...
}

可以看到,对服务器返回的 InputStream 的读取,以及对图片的加载全都在这里了。当然这里其实处理了很多的逻辑,包括对图片的压缩,甚至还有旋转、圆角等逻辑处理,但是我们目前只需要关注主线逻辑就行了。decode() 方法执行之后,会返回一个 Bitmap 对象,那么图片在这里其实也就已经被加载出来了,剩下的工作就是如果让这个 Bitmap 显示到界面上,我们继续往下分析。

回到刚才的 StreamBitmapDecoder 当中,你会发现,它的 decode() 方法返回的是一个 Resource 对象。而我们从 Downsampler 中得到的是一个 Bitmap 对象,因此这里在第 18 行又调用了 BitmapResource.obtain() 方法,将 Bitmap 对象包装成了 Resource 对象。代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class BitmapResource implements Resource<Bitmap> {
private final Bitmap bitmap;
private final BitmapPool bitmapPool;
/**
* Returns a new {@link BitmapResource} wrapping the given {@link Bitmap} if the Bitmap is non-null or null if the
* given Bitmap is null.
*
* @param bitmap A Bitmap.
* @param bitmapPool A non-null {@link BitmapPool}.
*/
public static BitmapResource obtain(Bitmap bitmap, BitmapPool bitmapPool) {
if (bitmap == null) {
return null;
} else {
return new BitmapResource(bitmap, bitmapPool);
}
}
public BitmapResource(Bitmap bitmap, BitmapPool bitmapPool) {
if (bitmap == null) {
throw new NullPointerException("Bitmap must not be null");
}
if (bitmapPool == null) {
throw new NullPointerException("BitmapPool must not be null");
}
this.bitmap = bitmap;
this.bitmapPool = bitmapPool;
}
@Override
public Bitmap get() {
return bitmap;
}
@Override
public int getSize() {
return Util.getBitmapByteSize(bitmap);
}
@Override
public void recycle() {
if (!bitmapPool.put(bitmap)) {
bitmap.recycle();
}
}
}

BitmapResource 的源码也非常简单,经过这样一层包装之后,如果我还需要获取 Bitmap,只需要调用 Resource 的 get() 方法就可以了。

然后我们需要一层层继续向上返回,StreamBitmapDecoder 会将值返回到 ImageVideoBitmapDecoder 当中,而 ImageVideoBitmapDecoder 又会将值返回到 GifBitmapWrapperResourceDecoder 的 decodeBitmapWrapper() 方法当中。由于代码隔得有点太远了,我重新把 decodeBitmapWrapper() 方法的代码贴一下:

1
2
3
4
5
6
7
8
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);
}
return result;
}

可以看到,decodeBitmapWrapper() 方法返回的是一个 GifBitmapWrapper 对象。因此,这里在第 5 行,又将 Resource 封装到了一个 GifBitmapWrapper 对象当中。这个 GifBitmapWrapper 顾名思义,就是既能封装 GIF,又能封装 Bitmap,从而保证了不管是什么类型的图片 Glide 都能从容应对。我们顺便来看下 GifBitmapWrapper 的源码吧,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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;
}
}

还是比较简单的,就是分别对 gifResource 和 bitmapResource 做了一层封装而已,相信没有什么解释的必要。

然后这个 GifBitmapWrapper 对象会一直向上返回,返回到 GifBitmapWrapperResourceDecoder 最外层的 decode() 方法的时候,会对它再做一次封装,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public Resource<GifBitmapWrapper> decode(ImageVideoWrapper source, int width, int height) throws IOException {
ByteArrayPool pool = ByteArrayPool.get();
byte[] tempBytes = pool.getBytes();
GifBitmapWrapper wrapper = null;
try {
wrapper = decode(source, width, height, tempBytes);
} finally {
pool.releaseBytes(tempBytes);
}
return wrapper != null ? new GifBitmapWrapperResource(wrapper) : null;
}

可以看到,这里在第 11 行,又将 GifBitmapWrapper 封装到了一个 GifBitmapWrapperResource 对象当中,最终返回的是一个 Resource 对象。这个 GifBitmapWrapperResource 和刚才的 BitmapResource 是相似的,它们都实现的 Resource 接口,都可以通过 get() 方法来获取封装起来的具体内容。GifBitmapWrapperResource 的源码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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();
}
}
}

经过这一层的封装之后,我们从网络上得到的图片就能够以 Resource 接口的形式返回,并且还能同时处理 Bitmap 图片和 GIF 图片这两种情况。

那么现在我们可以回到 DecodeJob 当中了,它的 decodeFromSourceData() 方法返回的是一个 Resource 对象,其实也就是 Resource 对象了。然后继续向上返回,最终返回到 decodeFromSource() 方法当中,如下所示:

1
2
3
4
public Resource<Z> decodeFromSource() throws Exception {
Resource<T> decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
}

刚才我们就是从这里跟进到 decodeSource() 方法当中,然后执行了一大堆一大堆的逻辑,最终得到了这个 Resource 对象。然而你会发现,decodeFromSource() 方法最终返回的却是一个 Resource 对象,那么这到底是怎么回事呢?我们就需要跟进到 transformEncodeAndTranscode() 方法来瞧一瞧了,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
long startTime = LogTime.getLogTime();
Resource<T> transformed = transform(decoded);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transformed resource from source", startTime);
}
writeTransformedToCache(transformed);
startTime = LogTime.getLogTime();
Resource<Z> result = transcode(transformed);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transcoded transformed from source", startTime);
}
return result;
}
private Resource<Z> transcode(Resource<T> transformed) {
if (transformed == null) {
return null;
}
return transcoder.transcode(transformed);
}

首先,这个方法开头的几行transform还有cache,这都是我们后面才会学习的东西,现在不用管它们就可以了。需要注意的是第9行,这里调用了一个transcode()方法,就把Resource对象转换成Resource对象了。

而 transcode() 方法中又是调用了 transcoder 的 transcode() 方法,那么这个 transcoder 是什么呢?其实这也是 Glide 源码特别难懂的原因之一,就是它用到的很多对象都是很早很早之前就初始化的,在初始化的时候你可能完全就没有留意过它,因为一时半会根本就用不着,但是真正需要用到的时候你却早就记不起来这个对象是从哪儿来的了。

那么这里我来提醒一下大家吧,在第二步 load() 方法返回的那个 DrawableTypeRequest 对象,它的构建函数中去构建了一个 FixedLoadProvider 对象,然后我们将三个参数传入到了 FixedLoadProvider 当中,其中就有一个 GifBitmapWrapperDrawableTranscoder 对象。后来在 onSizeReady() 方法中获取到了这个参数,并传递到了 Engine 当中,然后又由 Engine 传递到了 DecodeJob 当中。因此,这里的 transcoder 其实就是这个 GifBitmapWrapperDrawableTranscoder 对象。那么我们来看一下它的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class GifBitmapWrapperDrawableTranscoder implements ResourceTranscoder<GifBitmapWrapper, GlideDrawable> {
private final ResourceTranscoder<Bitmap, GlideBitmapDrawable> bitmapDrawableResourceTranscoder;
public GifBitmapWrapperDrawableTranscoder(
ResourceTranscoder<Bitmap, GlideBitmapDrawable> bitmapDrawableResourceTranscoder) {
this.bitmapDrawableResourceTranscoder = bitmapDrawableResourceTranscoder;
}
@Override
public Resource<GlideDrawable> transcode(Resource<GifBitmapWrapper> toTranscode) {
GifBitmapWrapper gifBitmap = toTranscode.get();
Resource<Bitmap> bitmapResource = gifBitmap.getBitmapResource();
final Resource<? extends GlideDrawable> result;
if (bitmapResource != null) {
result = bitmapDrawableResourceTranscoder.transcode(bitmapResource);
} else {
result = gifBitmap.getGifResource();
}
return (Resource<GlideDrawable>) result;
}
...
}

这里我来简单解释一下,GifBitmapWrapperDrawableTranscoder 的核心作用就是用来转码的。因为 GifBitmapWrapper 是无法直接显示到 ImageView 上面的,只有 Bitmap 或者 Drawable 才能显示到 ImageView 上。因此,这里的 transcode() 方法先从 Resource 中取出 GifBitmapWrapper 对象,然后再从 GifBitmapWrapper 中取出 Resource 对象。

接下来做了一个判断,如果 Resource 为空,那么说明此时加载的是 GIF 图,直接调用 getGifResource() 方法将图片取出即可,因为 Glide 用于加载 GIF 图片是使用的 GifDrawable 这个类,它本身就是一个 Drawable 对象了。而如果 Resource 不为空,那么就需要再做一次转码,将 Bitmap 转换成 Drawable 对象才行,因为要保证静图和动图的类型一致性,不然逻辑上是不好处理的。

这里在第 15 行又进行了一次转码,是调用的 GlideBitmapDrawableTranscoder 对象的 transcode() 方法,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class GlideBitmapDrawableTranscoder implements ResourceTranscoder<Bitmap, GlideBitmapDrawable> {
private final Resources resources;
private final BitmapPool bitmapPool;
public GlideBitmapDrawableTranscoder(Context context) {
this(context.getResources(), Glide.get(context).getBitmapPool());
}
public GlideBitmapDrawableTranscoder(Resources resources, BitmapPool bitmapPool) {
this.resources = resources;
this.bitmapPool = bitmapPool;
}
@Override
public Resource<GlideBitmapDrawable> transcode(Resource<Bitmap> toTranscode) {
GlideBitmapDrawable drawable = new GlideBitmapDrawable(resources, toTranscode.get());
return new GlideBitmapDrawableResource(drawable, bitmapPool);
}
...
}

可以看到,这里 new 出了一个 GlideBitmapDrawable 对象,并把 Bitmap 封装到里面。然后对 GlideBitmapDrawable 再进行一次封装,返回一个 Resource 对象。

现在再返回到 GifBitmapWrapperDrawableTranscoder 的 transcode() 方法中,你会发现它们的类型就一致了。因为不管是静图的 Resource 对象,还是动图的 Resource 对象,它们都是属于父类 Resource 对象的。因此 transcode() 方法也是直接返回了 Resource,而这个 Resource 其实也就是转换过后的 Resource了。

那么我们继续回到 DecodeJob当中,它的 decodeFromSource() 方法得到了 Resource 对象,当然也就是 Resource 对象。然后继续向上返回会回到 EngineRunnable 的 decodeFromSource() 方法,再回到 decode() 方法,再回到 run() 方法当中。那么我们重新再贴一下 EngineRunnable run() 方法的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
resource = decode();
} 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);
}
}

也就是说,经过第 9 行 decode() 方法的执行,我们最终得到了这个 Resource 对象,那么接下来就是如何将它显示出来了。可以看到,这里在第 25 行调用了 onLoadComplete() 方法,表示图片加载已经完成了,代码如下所示:

1
2
3
private void onLoadComplete(Resource resource) {
manager.onResourceReady(resource);
}

这个 manager 就是 EngineJob 对象,因此这里实际上调用的是 EngineJob 的 onResourceReady() 方法,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
class EngineJob implements EngineRunnable.EngineRunnableManager {
private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
private final List<ResourceCallback> cbs = new ArrayList<ResourceCallback>();
...
public void addCallback(ResourceCallback cb) {
Util.assertMainThread();
if (hasResource) {
cb.onResourceReady(engineResource);
} else if (hasException) {
cb.onException(exception);
} else {
cbs.add(cb);
}
}
@Override
public void onResourceReady(final Resource<?> resource) {
this.resource = resource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
private void handleResultOnMainThread() {
if (isCancelled) {
resource.recycle();
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
engineResource.acquire();
listener.onEngineJobComplete(key, engineResource);
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource);
}
}
engineResource.release();
}
@Override
public void onException(final Exception e) {
this.exception = e;
MAIN_THREAD_HANDLER.obtainMessage(MSG_EXCEPTION, this).sendToTarget();
}
private void handleExceptionOnMainThread() {
if (isCancelled) {
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received an exception without any callbacks to notify");
}
hasException = true;
listener.onEngineJobComplete(key, null);
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
cb.onException(exception);
}
}
}
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();
} else {
job.handleExceptionOnMainThread();
}
return true;
}
return false;
}
}
...
}

可以看到,这里在 onResourceReady() 方法使用 Handler 发出了一条 MSG_COMPLETE 消息,那么在 MainThreadCallback 的 handleMessage() 方法中就会收到这条消息。从这里开始,所有的逻辑又回到主线程当中进行了,因为很快就需要更新 UI 了。

然后在第 72 行调用了 handleResultOnMainThread() 方法,这个方法中又通过一个循环,调用了所有 ResourceCallback 的 onResourceReady() 方法。那么这个 ResourceCallback 是什么呢?答案在 addCallback() 方法当中,它会向 cbs 集合中去添加 ResourceCallback。那么这个 addCallback() 方法又是哪里调用的呢?其实调用的地方我们早就已经看过了,只不过之前没有注意,现在重新来看一下 Engine 的 load() 方法,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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 engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
...
}

这次把目光放在第 18 行上面,看到了吗?就是在这里调用的 EngineJob 的 addCallback() 方法来注册的一个 ResourceCallback。那么接下来的问题就是,Engine.load() 方法的 ResourceCallback 参数又是谁传过来的呢?这就需要回到 GenericRequest 的 onSizeReady() 方法当中了,我们看到 ResourceCallback 是 load() 方法的最后一个参数,那么在 onSizeReady() 方法中调用 load() 方法时传入的最后一个参数是什么?代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,
ResourceCallback {
...
@Override
public void onSizeReady(int width, int height) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
width = Math.round(sizeMultiplier * width);
height = Math.round(sizeMultiplier * height);
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadedFromMemoryCache = true;
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation,
transcoder, priority, isMemoryCacheable, diskCacheStrategy, this);
loadedFromMemoryCache = resource != null;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
...
}

请将目光锁定在第 29 行的最后一个参数,this。没错,就是 this。GenericRequest 本身就实现了 ResourceCallback 的接口,因此 EngineJob 的回调最终其实就是回调到了 GenericRequest 的 onResourceReady() 方法当中了,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public void onResourceReady(Resource<?> resource) {
if (resource == null) {
onException(new Exception("Expected to receive a Resource<R> with an object of " + transcodeClass
+ " inside, but instead got null."));
return;
}
Object received = resource.get();
if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
releaseResource(resource);
onException(new Exception("Expected to receive an object of " + transcodeClass
+ " but instead got " + (received != null ? received.getClass() : "") + "{" + received + "}"
+ " inside Resource{" + resource + "}."
+ (received != null ? "" : " "
+ "To indicate failure return a null Resource object, "
+ "rather than a Resource object containing null data.")
));
return;
}
if (!canSetResource()) {
releaseResource(resource);
// We can't set the status to complete before asking canSetResource().
status = Status.COMPLETE;
return;
}
onResourceReady(resource, (R) received);
}
private void onResourceReady(Resource<?> resource, R result) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
isFirstResource)) {
GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
target.onResourceReady(result, animation);
}
notifyLoadSuccess();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Resource ready in " + LogTime.getElapsedMillis(startTime) + " size: "
+ (resource.getSize() * TO_MEGABYTE) + " fromCache: " + loadedFromMemoryCache);
}
}

这里有两个 onResourceReady() 方法,首先在第一个 onResourceReady() 方法当中,调用 resource.get() 方法获取到了封装的图片对象,也就是 GlideBitmapDrawable 对象,或者是 GifDrawable 对象。然后将这个值传入到了第二个 onResourceReady() 方法当中,并在第 36 行调用了 target.onResourceReady() 方法。

那么这个 target 又是什么呢?这个又需要向上翻很久了,在第三步 into() 方法的一开始,我们就分析了在 into() 方法的最后一行,调用了 glide.buildImageViewTarget() 方法来构建出一个 Target,而这个 Target 就是一个 GlideDrawableImageViewTarget 对象。

那么我们去看 GlideDrawableImageViewTarget 的源码就可以了,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class GlideDrawableImageViewTarget extends ImageViewTarget<GlideDrawable> {
private static final float SQUARE_RATIO_MARGIN = 0.05f;
private int maxLoopCount;
private GlideDrawable resource;
public GlideDrawableImageViewTarget(ImageView view) {
this(view, GlideDrawable.LOOP_FOREVER);
}
public GlideDrawableImageViewTarget(ImageView view, int maxLoopCount) {
super(view);
this.maxLoopCount = maxLoopCount;
}
@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);
this.resource = resource;
resource.setLoopCount(maxLoopCount);
resource.start();
}
@Override
protected void setResource(GlideDrawable resource) {
view.setImageDrawable(resource);
}
@Override
public void onStart() {
if (resource != null) {
resource.start();
}
}
@Override
public void onStop() {
if (resource != null) {
resource.stop();
}
}
}

在 GlideDrawableImageViewTarget 的 onResourceReady() 方法中做了一些逻辑处理,包括如果是 GIF 图片的话,就调用 resource.start() 方法开始播放图片,但是好像并没有看到哪里有将 GlideDrawable 显示到 ImageView 上的逻辑。

确实没有,不过父类里面有,这里在第 25 行调用了 super.onResourceReady() 方法,GlideDrawableImageViewTarget 的父类是 ImageViewTarget,我们来看下它的代码吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
}
}
protected abstract void setResource(Z resource);
}

可以看到,在 ImageViewTarget 的 onResourceReady() 方法当中调用了 setResource() 方法,而 ImageViewTarget 的 setResource() 方法是一个抽象方法,具体的实现还是在子类那边实现的。

那子类的 setResource() 方法是怎么实现的呢?回头再来看一下 GlideDrawableImageViewTarget 的 setResource() 方法,没错,调用的 view.setImageDrawable() 方法,而这个 view 就是 ImageView。代码执行到这里,图片终于也就显示出来了。

那么,我们对 Glide 执行流程的源码分析,到这里也终于结束了。

真是好长的一篇文章,这也可能是我目前所写过的最长的一篇文章了。如果你之前没有读过 Glide 的源码,真的很难相信,这短短一行代码:

1
Glide.with(this).load(url).into(imageView);