Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。
Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的Api是如此的灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。
虽然Glide 的主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求。
官方github链接地址:https://github.com/bumptech/glide
简体中文文档:https://muyangmin.github.io/glide-docs-cn/
本篇基于4.10.0版本做分析
Glide.with(fragment).load(url).into(imageView)
Glide.with(this)
.load(url)
.placeholder(xx)
.error(xx)
.override(w,h)
.fitCenter(xx)
.centerCrop(xx)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.priority(Priority.HIGH)
.into(imageView)
主流程是整个glide的脉络主线,只有牢记glide主流程,才不会陷入glide细节代码中,更好理解glide
先从glide最简单的使用开始
Glide.with(this).load(url).into(imageView)
可以看到Glide类提供了多个静态with方法,参数类型不同而已,之所以这么做
// Glide.java
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
...
看下with(Context)方法,可以知道返回的其实是一个RequestManager类,RequestManagerRetriever类可以理解为专门生产RequestManager的类,看下它的get方法
// RequestManagerRetriever.java
@NonNull
public RequestManager get(@NonNull 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
// Only unwrap a ContextWrapper if the baseContext has a non-null application context.
// Context#createPackageContext may return a Context without an Application instance,
// in which case a ContextWrapper may be used to attach one.
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
// 如果传入是一个全局application,则返回的一个单例RequestManager
return getApplicationManager(context);
}
最后一句进去看下
可以看到这里面其实返回的是一个applicationManager的对象,并且是一个单例;我们可以推测这个RequestManager其实与with传入的组件生命周期管理起来,那么Glide是如何将RequestManager与activity、fragment管理起来的?我们以with(Activity为例)
// RequestManagerRetriever.java
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
可以看到glide首先是判断如果是运行在后台线程,直接返回一个全局的RequestManager,否则的话,从当前activity上挂载的一个无UI界面的glideFragment中获取这个RequestManager
@NonNull
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
可以看到glide首先从名为current的fragment获取requestManger没有就创建并存储到current中去;这里需要注意到RequestManager构造器中传入了fragment.glideLifecycle,之所以这样所是为了把拥有生命周期的fragment和RequestManager关联起来了,让RequestManager拥有感知生命周期的能力;通过上述代码我们可以简单理解一个activity对象拥有一个RequestManager(其他业务fragment暂不考虑)
因为glide作为一个图片库,它无法感知到activity或fragment的生命周期,glide为了感知它,通过创建无UI的fragment实现了RequestManager可以监听activity、fragment生命周期;这样可以做到无侵入,且可以有效较少资源消耗
下面的代码展示了glide是如何获取、创建、存储SupportRequestManagerFragment对象的
@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
// 1. 先从fm中取fragment
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
// 2. 其次从pendingSupportRequestManagerFragments map对象中取
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
// 3. 找不到就手动创建fragment
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
// 4. 存储到map中
pendingSupportRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
// 发送一个消息,从pendingSupportRequestManagerFragments中移除fragment
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
可以看到getSupportRequestManagerFragment
先是从fm寻找,如果没有从一个pendingSupportRequestManagerFragments的map对象(key为fm)寻找,如果都没有说明fragment没有被创建过,需要手动创建,这里把fragment先存储到临时map中是因为fm存储fragment是通过消息队列方式的,不能立马从fm获取,所以pendingSupportRequestManagerFragments只是临时存储作用,后面glide会通过handler发送消息,将fragment从map中移除
要回答这个问题,我们需要研究下SupportRequestManagerFragment构造器
可以看到SupportRequestManagerFragment默认构造器中传入了一个ActivityFragmentLifecycle对象,这个对象的作用其实就是将fragment的生命周期事件传递给自己的订阅者,实现其生命周期的转发
想想看如果RequestManger实现了LifecycleListener接口,并注册到了ActivityFragmentLifecycle对象中会发生什么?
没错,结果就是RequestManager能够感知到fragment的生命周期了,
我们来看下代码发现RequestManger确实实现了LifeCycleListener,同时在构造器方法中实现了对lifecycle的注册
至此 glide通过一个无UI的fragment实现了让RequestManager感知生命周期能力,以一张流程图总结生命周期事件传递分发
下图中就是RequestManager的部分实现
可以看到RequestManager里面实现了onStart、onStop、onDestroy方法
这些请求从哪来的呢?谁创建的?
带着这个疑问我们继续来看load方法
因为glide支持加载远程图片,本地资源文件,所以load这里是个重载方法,这个比较好理解
这里我们从常用的load(String)分析
/**
* Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(String)}.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
可以load方法内部是创建了一个RequestBuilder并链式调用其load方法,RequestBuilder它可以通过给定的model(图片url)来加载成一个resouces(Drawable)
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
/**
* Attempts to load the resource using any registered {@link
* com.bumptech.glide.load.ResourceDecoder}s that can decode the given resource class or any
* subclass of the given resource class.
*
* @param resourceClass The resource to decode.
* @return A new request builder for loading the given resource class.
*/
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
as使用来创建一个加载指定资源类型的RequestBuilder方法,接下来看下其load方法
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
内部实现非常简单,就是把我们需要请求图片的url(在glide中可以理解为model)保存到RequestBuilder,顺便提下RequestBuilder继承了BaseRequestOptions,里面有我们所熟悉的centerCrop图片裁剪,占位图,内存缓存,磁盘缓存策略,优先级定义等方法
这些方法都可以理解为相关的配置信息,这些配置的信息将在后续流程使用到,可以看到我们在load中并没有找到我们的资源请求的创建?答案是在into方法中,在篇2给讲解到