Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术
Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的Api是如此的灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。
虽然Glide 的主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求。
Glide 使用简明的流式语法API,这是一个非常棒的设计,因为它允许你在大部分情况下一行代码搞定需求:
Glide.with(fragment)
.load(url)
.into(imageView);
Glide 充分考虑了Android图片加载性能的两个关键方面:
为了让用户拥有良好的App使用体验,图片不仅要快速加载,而且还不能因为过多的主线程I/O或频繁的垃圾回收导致页面的闪烁和抖动现象。
Glide使用了多个步骤来确保在Android上加载图片尽可能的快速和平滑:
关于Glide详细介绍,可以参考Glide官方文档
Glide官方文档中文版
何谓剖析:「化整为零,分而治之」
从它的使用开始,我们看一下每个步骤,本篇文章将按照下图所示,一步步对Glide源码进行完整的剖析
Glide.with(this).load(url).into(imageView);
// 参数说明
// 参数1:Context context
// Context对于很多Android API的调用都是必须的,这里就不多说了
// 参数2:String imageUrl:被加载图像的Url地址
// 大多情况下,一个字符串代表一个网络图片的URL
// 参数3:ImageView targetImageView:图片最终要展示的地方。
所以Glide的源码分析分为三步:
我们的 APP 第一次使用 Glide 加载一张图片,那么流程如下
Glide 类算是个全局的配置类,Encoder、Decoder、ModelLoader、Pool 等等都在这里设置,此外还提供了创建 RequestManager 的接口(Glide#with() 方法)。
使用 Glide 时会最先调用 Glide#with() 方法创建 RequestManager,Glide 中的 with() 方法有五个重载:
RequestManager with(Context context)
RequestManager with(android.app.Activity)
RequestManager with(android.app.Fragment)
RequestManager with(android.support.v4.app.Fragment)
RequestManager with(android.support.v4.app.FragmentActivity)
Glide#with() 方法会将 RequestManager 的创建委托给 RequestManagerRetriever,RequestManagerRetriever 为单例类,调用 get(Context) 创建 RequestManager。
具体源码分析:基于最新的源码v4.10.1
public class Glide {
...
// with()重载种类非常多,根据传入的参数可分为:
// 1. 非Application类型的参数(Activity & Fragment )
// 2. Application类型的参数(Context)
// 3. 直接传入一个view,通过view.getContext()获取Context
// 参数1:Application类型
@NonNull
public static RequestManager with(@NonNull Context context) {
//1:获取Retriever 单例实现
//2:通过Retriever获取RequestManager&绑定加载的生命周期
return getRetriever(context).get(context);
}
// 参数2:非Application类型(Activity & Fragment )
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getContext()).get(fragment);
}
//这个应该是后面版本加的
@NonNull
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
...
}
<-- 分析1:RequestManagerRetriever对象的实例 get()-->
// 作用:
// 1. 获取RequestManager对象
// 2. 将图片加载的生命周期与Activity/Fragment的生命周期进行绑定
//入口方法,实际就是对context类型进行判断,然后分别调用对应的方法
@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 && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
public class RequestManagerRetriever implements Handler.Callback {
...
// 实例的get()重载种类很多,参数分为:(与with()类似)
// 1. Application类型(Context)
// 2. 非Application类型(Activity & Fragment )- >>分析3
// 下面会详细分析
// 参数1:Application类型(Context)会获取到一个单例对象
@NonNull
private RequestManager getApplicationManager(@NonNull Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
// 参数2:非Application类型(Activity & Fragment )
// 将Glide加载图片的生命周期与Activity生命周期同步的具体做法:向当前的Activity添加一个隐藏的Fragment
// 原因:因Fragment的生命周期 与 Activity 的是同步的,通过添加隐藏的Fragment 从而监听Activity的生命周期,从而实现Glide加载图片的生命周期与Activity的生命周期 进行同步。
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
//===》分析3
return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
public RequestManager get(@NonNull FragmentActivity activity) {
// 逻辑同上,此处不作过多描述
...
}
public RequestManager get(Fragment fragment) {
// 逻辑同上,此处不作过多描述
...
}
//直接通过View获取RequestManager
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull View view) {
if (Util.isOnBackgroundThread()) {
return get(view.getContext().getApplicationContext());
}
Preconditions.checkNotNull(view);
Preconditions.checkNotNull(
view.getContext(), "Unable to obtain a request manager for a view without a Context");
Activity activity = findActivity(view.getContext());
// The view might be somewhere else, like a service.
if (activity == null) {
return get(view.getContext().getApplicationContext());
}
if (activity instanceof FragmentActivity) {
Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
return fragment != null ? get(fragment) : get((FragmentActivity) activity);
}
android.app.Fragment fragment = findFragment(view, activity);
if (fragment == null) {
return get(activity);
}
return get(fragment);
}
}
<-- 分析2:Glide.get(context) -->
/**
* 获取一个Glide单例
*
* @return the singleton
*/
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
//获取注解处理器自动生成的一些配置
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
<--分析3:fragmentGet() -->
// 作用:
// 1. 创建Fragment
// 2. 向当前的Activity中添加一个隐藏的Fragment
// 3. 将RequestManager与该隐藏的Fragment进行绑定(通过RequestManagerFragment)
@SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"})
@Deprecated
@NonNull
private RequestManager fragmentGet(
@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
// 获取RequestManagerFragment
// 作用:利用Fragment进行请求的生命周期管理
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
//利用manager获取RequestManager
RequestManager requestManager = current.getRequestManager();
// 若requestManager 为空,即首次加载初始化requestManager
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
//通过工厂创建requestManager
// 创建RequestManager传入Lifecycle实现类,如ActivityFragmentLifecycle
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
//调用setRequestManager设置到RequestManagerFragment
current.setRequestManager(requestManager);
}
return requestManager;
}
小结:with()是为得到一个RequestManager对象 从而将Glide加载图片周期 与Activity 和Fragment进行绑定,从而管理Glide加载图片周期
RequestBuilder<Drawable> load(@Nullable Bitmap bitmap);
RequestBuilder<Drawable> load(@Nullable Drawable drawable);
RequestBuilder<Drawable> load(@Nullable String string);
RequestBuilder<Drawable> load(@Nullable Uri uri);
RequestBuilder<Drawable> load(@Nullable File file);
RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId);
RequestBuilder<Drawable> load(@Nullable URL url);
RequestBuilder<Drawable> load(@Nullable byte[] model);
RequestBuilder<Drawable> load(@Nullable Object model);
//还有两个特别的load方法,用来下载图片文件
RequestBuilder<File> downloadOnly();
RequestBuilder<File> download(@Nullable Object model);
实际上,每一个重载方法都代表了Glide可以加载的一种资源的类型
public class RequestManager implements LifecycleListener {
// 仅贴出关键代码
//第一步,调用asDrawable()获取到Requestbuild
//第二步,调用RequestBuild的load(string)
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
//as方法
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
然后在看RequestBuilder对象的相关方法,这里比以往的版本逻辑更简单,只是简单设置加载的类型和一些简单的初始化操作。
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
implements Cloneable, ModelTypes<RequestBuilder<TranscodeType>> {
....
//此处只贴出关键代码
//1.load(string)方法
@Override
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
//2. laodGeneric()方法
//设置需要加载的资源的类型
@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
//设置一个标记,在into方法调用时候,会判断是否为true,如果为false,表示
//还没有调用load()方法,会抛出非法参数的异常
// throw new IllegalArgumentException("You must call #load() //before calling #into()");
isModelSet = true;
return this;
}
}
至此,第2步的 load()分析完成,相比与以往版本,这个版本重构了一些load()的逻辑,变得更加简单,清晰明了。
RequestBuilder 用来构建请求,例如设置 RequestOption、缩略图、加载失败占位图等等。
上面说到的 RequestManager 中诸多的 load 重载方法,同样也对应 RequestBuilder 中的重载 load 方法,一般来说 load 方法之后就是调用 into 方法设置 ImageView 或者 Target,into 方法中最后会创建 Request,并启动,into()也是RequetBuilder的方法
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
//注释1:必须在主线程调用
Util.assertMainThread();
//检查view是否为null,为null会抛出空指针异常
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
//根据ScaleType,更新配置信息
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
//最后调用另一个重载方法,真正创建请求并加载
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
创建 Request的into方法,源码如下所示:
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
//在requestManager中untrack targer
requestManager.clear(target);
target.setRequest(request);
//在requestManager将target和request关联起来
requestManager.track(target, request);
return target;
}
//=====看requestManager的track 方法======
//=====看requestManager的润Request方法===
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
//这里就开始跟踪一个请求,可能开始,可能被清除,也可能加入到pendingRequests队列中
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
====
到这里,with(),load(),into 方法就分析完成了,总结:
另外几个重要的接口和类:
类声明:
public interface Target<R> extends LifecycleListener {
/** Indicates that we want the resource in its original unmodified width and/or height. */
int SIZE_ORIGINAL = Integer.MIN_VALUE;
void onLoadStarted(@Nullable Drawable placeholder);
void onLoadFailed(@Nullable Drawable errorDrawable);
void onResourceReady(@NonNull R resource, @Nullable Transition<? super R> transition);
void onLoadCleared(@Nullable Drawable placeholder);
void getSize(@NonNull SizeReadyCallback cb);
void removeCallback(@NonNull SizeReadyCallback cb);
void setRequest(@Nullable Request request);
@Nullable
Request getRequest();
}
显然:Target 代表一个可被 Glide 加载并且具有生命周期的资源。简单说,就是把图片资源放到哪里去,比如常用的显示到ImageView上,就对应ImageViewTarget。并且Target 具有生命周期感知的能力(继承自LifeCycle接口)
当我们调用 RequestBuilder#into 方法时会根据传入参数创建对应类型的 Target 实现类。
那么 Target 在 Glide 的整个加载流程中到底扮演者什么样的角色呢?Target 的中文意思为:目标,实际上就是指加载完成后的图片应该放在哪, Target 默认提供了很多很有用的实现类,当然我们也可以自定义 Target。
Glide 默认提供了用于放在 ImageView 上的 ImageViewTarget(以及其各种子类)、放在 AppWidget 上的 AppWidgetTarget、用于同步加载图片的 FutureTarget(只有一个实现类:RequestFutureTarget)等等,下面分别来看一下。
Target 的实现类
这个是抽象类,负责加载 Bitmap、Drawable 并且放到 View 上。
上文提到过,如果在 View 还未初始化完成时就调用了 Glide 加载图片会等待加载完成再去执行 onSizeReady 方法,那如何监听 View 初始化完成呢?
CustomViewTarget 就针对这个问题给出了解决方案,其中会调用 View#addOnAttachStateChangeListener 方法添加一个监听器,这个监听器可以监听到 View 被添加到 Widow 以及移除 Window 时的事件,从而更好的管理 Request 生命周期。
另外,构建好的 Request 会通过 View#setTag 方法存入 View 中,后面再通过 View#getTag 方法获取。
但这个抽象类并没有实现类,也没有被使用过,View 相关的 Target 都是继承 ViewTarget 抽象基类,但这个类已经被标记为过期类了,推荐将 ViewTarget 替换成 CustomViewTarget 使用。
这个类又继承了抽象类 BaseTarget,这个基类里只是实现了 Target 接口的 setRequest 以及 getRequest 方法。
ViewTarget 基本上类似 CustomViewTarget ,只是具体的实现上有点不同。
听名字就知道,这是加载到 ImageView 上的 Target,继承了 ViewTarget,同样也是个抽象类。
构造器中限定了必须传入 ImageView 或者其子类,图片数据加载完成后会回调其中的 onResourceReady 方法,第一步是将图片设置给 ImageView,第二部是判断是否需要使用动画,需要的话就执行动画。
ImageViewTarget 的实现类比较多,总共有 5 个,但内容都很简单,主要用于区分加载的资源时 Bitmap 类型还是 Drawable 类型,这个在构建请求时确定,默认的加载请求最终都是 Drawable 类型,但如果构建请求时调用了 asBitmap 方法那就资源就会被转成 Bitmap 类型,另外一个就是资源使用缩略图展示。
这是用来同步加载图片的 Target,调用 RequestBuilder#submit 将会返回一个 FutureTarget,调用 get 方法即可获取到加载的资源对象。
用于将下载的 Bitmap 设置到 RemoteView 上。
与 AppWidgetTarget 类似,不同的是这是用来将 Bitmap 设置到 Notification 中的 RemoteView 上。
以上就是一些常用的Target 了
module 包下面的 GlideModel 比较重要
这是用来延迟设置 Glide 相关参数的,我们可以通过这个接口使 Glide 在初始化时应用我们的设置,因为 Glide 是单例类,通过这个设置可以保证在 Glide 单例类初始时,所有请求发起之前应用到 Glide。