一 Glide整体流程图
Glide源码非常复杂,如果不带目的的去看源码,我相信很快你就晕了,我建议还是带问题的去看源码比较容易的,不然你很容易迷糊的
二 Requset的创建和发送
问题:Glide的那些图片请求都去了那里?
我们先来看一下Glide的简单使用:
RequestManager resquestManager = Glide.with(this);
DrawableTypeRequest<Integer> drawableTypeRequest = resquestManager.load(R.drawable.ic_launcher_background);
Target<GlideDrawable> into = drawableTypeRequest.placeholder(R.drawable.test)。into(imageView);
2.1 核心类
- RequestManager:进行requests随Activity或Fragment生命周期管理,这个是Glide强大功能之一,可以避免内存损耗和泄露
- GenericRequestBuilder:使用建造者模式创建Request,其中的into()方法比较关键;针对不同格式的图片,Glide分别做了它们的request builder的实现。
- GenericRequest:实现了Request接口,包含request状态和request操作API,如begin(), cancel(), clear(), pause()。 同时它实现了ResourceCallback接口,在获取图片数据exception时回调
- RequestTracker:这个是request的管理类,主要包含有两个集合,一个是requests,用来存储正在执行的request;一个是pendingRequests,用来存储处于暂停等待的request
- Target:图片的目标实体,相当于MVC中的View。可以简单的理解为对View的适配,Glide在加载完图片的时候,可以通过回调来监听图片加载的情况或者直接对View进行图片的设置,主要的实现类有SimpleTarget,ViewTarget
2.2 源码剖析
首先我们通过with()方法获得一个RequestManager 对象,这个我们先不看,里面代码太多,而且没有我们要找的request请求,我们直接看into()方法:
drawableTypeRequest:
@Override
public Target<GlideDrawable> into(ImageView view) {
return super.into(view);
}
GenericRequestBuilder:
//相信大家在看源码的时候经常能看到Target这个类,这里大家可以理解为Glide对传入的View的一次封装,同时添加了LifecycleListener生命周期回调
public Target<TranscodeType> into(ImageView view) {
// 主线程判断,对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.
}
}
//这里把imageview封装成ImageViewTarget,继续调用into()方法
return into(glide.buildImageViewTarget(view, transcodeClass));
}
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();
// 此ViewTarget如果已经有request,则删除掉它,并从requestTracker集合中remove掉
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
// 创建Request,典型的builder模式调用。buildRequest()最后调用到obtainRequest(),这个方法会将Glide设置的参数都封装进去
Request request = buildRequest(target);
target.setRequest(request);
// target实现了lifecycleListener,故将它加入到lifecycle,这样在恰当的时机得到回调
lifecycle.addListener(target);
// 加入到requestTracker中,并run。它是数据获取的入口,后面重点分析
requestTracker.runRequest(request);
return target;
}
我们来看一下buildRequest()这个方法是如何对Request进行初始化的:
// buildRequest最终调用到obtainRequest方法,创建Request的关键方法,
// 将builder中的参数传入,这种方式传入参数太多,个人觉得不优雅,可以创建一个RequestParams数据类来存放参数
GenericRequestBuilder:
private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
RequestCoordinator requestCoordinator) {
// 看到这么一大段是不是觉得很懵逼了,我也觉得这是Glide写的挺不优雅的一个地方
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);
}
//继续来看一下GenericRequest.obtain()方法
GenericRequest:
// GenericRequest类,builder中传入的参数最终大部分设到了Request数据类中
public final class GenericRequest<A, T, Z, R> {
//参数太多,用args[]表示
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(args[]) {
@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>();
}
//这里通过init()方法一次给GenericRequest的参数赋值
request.init(args[]);
return request;
}
}
Ok,到这里我们终于创建了我们熟悉的request了,我们直接来看runRequest()这个方法:
RequestTracker:
public void runRequest(Request request) {
// 添加到全部request所在集合中
requests.add(request);
if (!isPaused) {
// begin()方法是request发送的入口,下面重点介绍
request.begin();
} else {
// 如果当前状态为paused,则不直接运行,而是添加到等待集合中。这一般发生在Activity或Fragment onStop()时
pendingRequests.add(request);
}
}
这段代码很简单,我们应该很容易猜出来,这里应该是根据Glide请求的状态来判断是否执行这个请求,其次这里出现了两个队列requests和pendingRequests,很显然,根据if (!isPaused)这个if判断,我们也知道这两个队列的用途,requests是用来存储正在运行的请求,pendingRequests则是用来存储等待或者未完成的请求
我们来看一下GenericRequest的begin()方法:
GenericRequest :
public void begin() {
// 记录时间
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
// 验证width和height是否合法
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// 发送request的关键所在,当获取了width height之后就可以向底层发送request请求了。后面详细说
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
// 数据load开始前,回调onLoadStarted,一般此时viewTarget会设置placeHolder
// 这是placeHolder占位图的实现原理,是不是顿时茅厕顿开了呀,哈哈~
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
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;
// 部分代码省略
// 采用engine来load数据,此处是最终request发送所在。涉及到cache等很多内容,后面一篇文章再详细分析
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));
}
}
}
// ImageViewTarget类,再回过头看看placeHolder是如何被设到ImageView里面的
public abstract class ImageViewTarget {
public void onLoadStarted(Drawable placeholder) {
// onLoadStarted中设置placeHolder到ImageView中,也就是占位符设置
view.setImageDrawable(placeholder);
}
}
into()方法是比较关键也比较麻烦的一个方法。Glide将View封装为了ViewTarget。into()方法分为request创建和request发送两大部分。创建采用Builder(GenericRequestBuilder)模式生成GenericRequest对象,发送则调用GenericRequest的begin方法,最终回调到底层Engine部分的相关方法。可以看出,经过Glide的层层封装,复杂的逻辑变得相对简单了很多。