android图片加载框架最早用的就是ImageLoader,并且对其源码专门弄了个Image Loader专栏分析其源码,后来项目中也用过Fresco以及Glide等,但是一直没有静下心来深入其Glide等源码内部了解他们的原理,所以本系列就基于Glide 4.2.0的版本对其进行剖析(4.x的版本与3.x的版本还是有些差异性的),因为Glide源码着实复杂,所以本篇作为Glide源码分析的第一篇文章不会涉及太深太杂的内容,需要徐徐图之。
Glide的使用方法也很简单,一句代码的事儿:
Glide.with(this).load(imageUrl).into(imageView);
如果将此代码按步骤进行划分的话,就可拆分成如下几行代码:
//构建RequestManager对象
RequestManager requestManager = Glide.with(this);
//构建
RequestBuilder<Drawable> requestBuilder = requestManager.load("http://");
Target target =requestBuilder.into(new ImageView(this));
上面三行代码也很简单:
1、调用Glide.with(this)创建一个RequestManager对象。
2、requestManager对象load一个图片URL返回RequestBuilder对象(其范型类型为Drawable)。
3、requestBuilder调用into方法使注入的ImageView显示对应url的图片
简简单单的代码背后其实隐藏大部分的逻辑,比如:
1、Glide内部是通过什么来发起http请求的?
2、Glide缓存是怎么工作的呢?
3、into方法执行后返回一个Target对象,为什么into都可以把任务完成了,还返回一个target对象干嘛的?Target是什么鬼?
4、RequsetBuilder顾名思义就是构建一个Request,那么Request在上面的代码中怎么没有体现?
仅仅从上面代码上来看,一脸蒙逼。。。就像看某类动作片都是马赛克一样,看不清细节,令人不痛快(奸笑)。下面就逐步开始剔除万恶的马赛克,揭露glide的内部细节。阅读Gide的源码着实比阅读ImageLoader的源码困难,在阅读的过程中也着实学了不少东西,下面正式开始吧。
RequestManager的创建过程
构建RequestManager的过程,是Glide通过调用with方法返回的,所以看看with方法都做了些什么(以activity为参数的with方法为例):
public static RequestManager with(Activity activity) {
return getRetriever(activity).get(activity);
}
witch方法先内部调用了getRetriever方法:
static RequestManagerRetriever getRetriever(Context context) {
return Glide.get(context).getRequestManagerRetriever();
}
getRetriever 方法返回一个RequestManagerRetriever对象,也就是说RequestManager对象是由RequestManagerRetriever来构建的,那么该对象是什么时候初始化的呢?先看看Glide的get方法:
public static Glide get(Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
如上所示Glide也是一个单利模式,checkAndInitializeGlide方法内部调用了initializeGlide方法来初始化Glide,剔除与本文无关的代码逻辑initializeGlide可以如下所示:
private static void initializeGlide(Context context) {
//省略部分代码
GlideBuilder builder = new GlideBuilder()
.setRequestManagerFactory(factory);
//省略部分代码
//通过构建着模式创建Glide对象
Glide glide = builder.build(applicationContext);
//省略部分代码
Glide.glide = glide;
}
上面省略了大量的代码后发现初始化Glide也是一个创建者模式,进入builder的build方法看看是怎么初始化的,现在我们在探讨RequestManagerRetriever的构建过程,所以还是省略了无关的代码来看:
public Glide build(Context context) {
//省略部分代码
//初始化Glide持有的RequestManagerRetriever对象
RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(requestManagerFactory);
return new Glide(
。。。。,
requestManagerRetriever,
。。。。);
}
可以看出Glide的RequestManagerRetriever初始化也很简单,另外需要注意的是该对象需要一个requestManagerFactory对象,如果requestManagerFactory对象客户端没有设置的话则使用glide默认的对象:
//熟悉的handler
private final Handler handler;
private final RequestManagerFactory factory;
public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
this.factory = factory != null ? factory : DEFAULT_FACTORY;
handler = new Handler(Looper.getMainLooper(), this );
}
默认的RequestManagerFactory为DEFAULT_FACTORY,
//构建RequestManager的工厂类
private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {
public RequestManager build(Glide glide, Lifecycle lifecycle,
RequestManagerTreeNode requestManagerTreeNode) {
return new RequestManager(glide, lifecycle, requestManagerTreeNode);
}
};
到此为止RequestManagerRetriever对象已经构建完毕,上文提到是通过RequestManagerRetriever对象的get方法来获取RequestManger对象的,所以让我们看看其get方法都做了些神马:
public RequestManager get(Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
android.app.FragmentManager fm = activity.getFragmentManager();
//调用fragmentGet方法返回RequestManager对象
return fragmentGet(activity, fm, null );
}
}
直接进入fragmentGet方法来看RequestManger的创建过程:
private RequestManager fragmentGet(Context context, android.app.FragmentManager fm,
android.app.Fragment parentHint) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
//初始化RequestManager
Glide glide = Glide.get(context);
requestManager =
factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
也就是说第一次初始化的时候调用上所说的工厂类DEFAULT_FACTORY来创建RequestManager.再次使用的话就是从RequestManagerFragment对象中获取了。
分析道这儿RequestManager对象的构建步骤分析完毕,总结下来也就是:
1、Glide初始化的时候先创建一个RequestManagerRetriever对象,并且该对象持有一个构建RequestManager对象的工厂接口RequestManagerFactory。该接口客户端可以使用自己的实现来构建RequestManager对象,也可以使用Glide 默认的工厂接口实现类DEFAULT_FACTORY。
2、通过RequestManagerRetriever的get方法来初始化RequestManager,说白了就是调用factory的build方法来完成RequestManager的构建。
另外需要注意的是,上面只是极尽简化的说明来RequestManager的构建过程,对于其内部大量的细节都暂时忽略,这样可以使得本文调理清晰点,至于更复杂的内部细节,会另开博文说明。
RequestBuilder 的构建
RequestManager对象构建完毕,那么通过requestManager.load(“http://”);方法返回的RequesBuilder又是如何构建的呢?
//requestManager的load方法
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
//asDrawable
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass);
}
如上所示load最终先调用asDrawable方法,然后调用as 方法将RequestBuidler的范型设置为Drawable并new一个RequestBuilder对象:
protected RequestBuilder(Glide glide, RequestManager requestManager,
Class<TranscodeType> transcodeClass) {
this.glide = glide;
this.requestManager = requestManager;
//注意该context是GlideContext对象
this.context = glide.getGlideContext();
//在本文中为Drawable.class
this.transcodeClass = transcodeClass;
//获取默认的请求参数
this.defaultRequestOptions = requestManager.getDefaultRequestOptions();
//获取默认的TransitionOptions对象
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.requestOptions = defaultRequestOptions;
}
asDrawable方法调用完毕后就调用load(model)方法:
public RequestBuilder<TranscodeType> load(@Nullable Object model) {
return loadGeneric(model);
}
//loadGeneric
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;//image url
isModelSet = true;
return this;
}
如上所示load 方法进而调用了loadGeneric方法,该方法就是设置了model属性(再此可以看为图片的url)和isModelSet变量
到此为止RequestBuilder对象也就构建完毕了,那么RequestBuilders是干什么呢?顾名思义,该对象也是使用了构建者模式,目的就是构建Request对象!!!requestBuilder对象创建完成后我们就可以调用into方法来显示图片了:
Target简单说明
public Target<TranscodeType> into(ImageView view) {
//省略对图片设置参数的处理代码
return into(context.buildImageViewTarget(view, transcodeClass), requestOptions);
}
into方法最终调用了另外一个into重载方法,在调用重载方法之前先调用GlideContext对象的buildImageViewTarget方法,在Glide通过GlideBuilder调用Glide构造器创建的时候,在Glide构造器内部初始化来GlideContext对象,代码如下:
//创建ImageViewTargetFactory对象
ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
//初始化GlideContext对象
glideContext =
new GlideContext(
context, registry, imageViewTargetFactory, defaultRequestOptions,
defaultTransitionOptions, engine, logLevel);
现在我们来看看GlideContext的buildImageViewTarget都做了些神马
public <X> Target<X> buildImageViewTarget(ImageView imageView, Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
代码很简单就是调用了ImageViewTargetFactory来创建一个Target:
public class ImageViewTargetFactory {
@SuppressWarnings("unchecked")
public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return (Target<Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (Target<Z>) new DrawableImageViewTarget(view);
} else {
//抛异常
}
}
}
因为上文我们传的是Drawable,所以此时的工厂类返回的是一个DrawableImageViewTarget对象,该对象持有一个目标ImageView的引用。buildImageViewTarget调用完毕后紧接着将生成的target对象交给了into重载方法,如下:
public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
return into(target, getMutableOptions());
}
该into重载方法继而有调用了另外一个重载方法:
//该方法最终也是返回一个Target
private <Y extends Target<TranscodeType>> Y into(@NonNull Y target, RequestOptions options) {
//省略部分代码
options = options.autoClone();
//构建reqeust对象
Request request = buildRequest(target, options);
//省略部分代码:此部分以后说明
requestManager.clear(target);
target.setRequest(request);
//注意此句,文章后面会有着重说明
requestManager.track(target, request);
return target;
}
至此into方法调用完毕,该方法执行的结果是返回一个Target接口的实现类,Glide本身提供类各种Target实现类,看下图先做个简单的直观印象,在本文中返回的是一个DrawableImageViewTarget对象:
Request对象简单说明
如上文所示我们先构建了RequestBuilder对象,根据其名称我们可以猜出RequestBuilder对象的作用就是创建Ruquest对象,在最后一个into方法调用的时候调用了如下代码来构建Request对象:
Request request = buildRequest(target, options);
在Glide中Request是一个接口,Glide对此接口有两个实现类:ThumbnailRequestCoordinator和SingleRequest。 现在让我们先看看buildRequest方法都做了什么:
private Request buildRequest(Target<TranscodeType> target, RequestOptions requestOptions) {
return buildRequestRecursive(target, null, transitionOptions, requestOptions.getPriority(),
requestOptions.getOverrideWidth(), requestOptions.getOverrideHeight(), requestOptions);
}
直接调用了buildRequestRecursive方法,所以进入其内部观看源码 :
private Request buildRequestRecursive(。。。) {
if (thumbnailBuilder != null) {
//省略大量代码
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
//省略大量代码
return coordinator;
} else if (thumbSizeMultiplier != null) {
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
//省略部分代码
return coordinator;
} else {
// Base case: no thumbnail.
//本文分析这个分支
return obtainRequest(target, requestOptions, parentCoordinator, transitionOptions, priority,
overrideWidth, overrideHeight);
}
}
因为在文章开头中我们只设置了URL,最终会走到obtainRequest方法中,该方法就是简单的return一个SingleRequest对象
return SingleRequest.obtain(
context,
model,//url
//省略部分参数,
context.getEngine(),
。。);
到此为止请求Request对象构建完毕,因为篇幅较长,此时来梳理下Glide的工作:
1、通过GlideBuilder来构建Glide对象
2、构建Glide对象的时候创建RequestManagerRetriever对象
3、通过RequestManangerRetriever对象持有的工厂类requestManagerFactory来构建RequestManager对象。
4、RequestManager调用load方法构建一个RequestBuilder对象
5、RequestBuilder对象在调用into方法的时候会调用buildRequest对象来build一个Request对象,同时会into方法会通过ImageViewTargetFactory工厂类来返回一个具体的Target对象。
- 发起网络请求,加载网络图片
那么Request对象创建完毕了,何时发起请求呢?还记得前文构建Request对象之后有一句代码么?在上面我特别加了注释 “注意此句,文章后面会有着重说明”:
//注意此句,文章后面会有着重说明
requestManager.track(target, request);
Request创建号之后会将生成的target(此处以DrawableIamgeViewTarget 为例)和request(此处分析SingleRequest)交给RequestManager对象来处理,顾名思义RequestManager的作用就是Manage Request!所以进入track内部:
void track(Target<?> target, Request request) {
targetTracker.track(target);
//执行reqeust
requestTracker.runRequest(request);
}
track方法调用来runRequest方法来执行请求:
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
//发起请求
request.begin();
} else {
pendingRequests.add(request);
}
}
runRequest方法也就是调用来request接口的begin 方法来发起请求或者说是执行异步加载:
/**
* Starts an asynchronous load.
*/
void begin();
以SingleReqeust为例,看看其begin方法都做了些什么:
public void begin() {
//省略部分代码
//如果资源已经存在
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
//此时资源还不存在
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
//设置图片的placeHolder图片
target.onLoadStarted(getPlaceholderDrawable());
}
}
总体来说上面的代码也很简单:
1、如果资源已经存在则调用onResourceReady方法
2、否则调用onSizeReady同时会设置placeholder
先分析其onResourceReady方法,该方法经过最终会调用 target.onResourceReady(result, animation);如果以DrawableImageViewTarget为例的话最终target.onResourceReady会调用DrawableImageViewTarget的setResource
protected void setResource(@Nullable Drawable resource) { //该view就是通过into方法传过来的ImageView
view.setImageDrawable(resource);
}
setResource也很简单,就是将生成的resource 这个Drawable对象交给ImageView的setImageDrawable方法,这样就可以完成图片的展示了。
至于onSizeReady鉴于其内部逻辑很复杂,就敬请阅读《Glide获取网络图片流程》
到此为止Glide内部的工作流程基本分析完毕,结合上文简单来说就是通过RequestBuilder创建一个Requset对象之后,调用request对像的begin发起异步加载的请求展示图片的过程。
如有不当之处,欢迎批评之正,共同学习。