深度学习 Android 图片加载框架 Glide (一) 切
前言
由于之前项目搭建的是 MVP 架构,由RxJava + Glide + OKHttp + Retrofit
等开源框架组合而成,之前也都是停留在使用层面上,没有深入的研究,最近打算把它们全部攻下,还没有关注的同学可以先关注一波,看完这个系列文章,(不管是面试还是工作中处理问题)相信你都在知道原理的情况下,处理问题更加得心应手。
更多系列教程GitHub白嫖入口:https://github.com/Timdk857/Android-Architecture-knowledge-2-
概述
相信大家在项目上应该都有用过或者了解过 Glide 图片加载框架吧,那么在用的时候是不是发现 Glide 一行代码就能对图片进行下载 -> 缓存 -> 显示 ,那么 Glide 内部它到底是怎么实现的?下面我们就来分析下 Glide 执行流程,脑袋里面先有一个对 Glide 源码总体执行流程的认识,我们就从下面最简单的代码开始分析:
Glide.with(Activity activity).load(String url).into(ImageView imageView);
上面这简简单单的一行代码,内部其实是极为的复杂。
ps: 建议阅读时间为 30 分钟,看完我相信你会有收获的。
with
在分析 with 源码之前,先看一下 Glide.with 执行的时序图,先对执行的流程有一个了解,我们在来分析代码干了些什么?
上面只是 Glide.with(Activity act) 的流程,那么上面涉及到的这几个类,他们的职责主要干什么的,我们来看看。
- Glide
- 主要做一些 init 工作,比如缓存,线程池,复用池的构建等等。
- RequestManagerRetriever
- 主要是获得一个
RequestManager
请求管理类,然后绑定一个 Fragment 。
- 主要是获得一个
- SupportRequestManagerFragment :
- 用于管理请求的生命周期。
- RequestManager
- 主要用于对请求的管理封装。
流程跟各个角色咱们介绍了,现在介绍下代码具体实现;
-
调用 with
Glide.with(Activity);
我们可以看下 with 这个源码函数,重载有很多。
@NonNull public static RequestManager with(@NonNull Context context) { return getRetriever(context).get(context); } @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.getActivity()).get(fragment); } /** @deprecated */ @Deprecated @NonNull public static RequestManager with(@NonNull android.app.Fragment fragment) { return getRetriever(fragment.getActivity()).get(fragment); } @NonNull public static RequestManager with(@NonNull View view) { return getRetriever(view.getContext()).get(view); }
其实常用的就 Activity,Fragment, Context 这 3 种形式,下面我们就以 Activity 为主。
-
getRetriever(activity)
@NonNull private static RequestManagerRetriever getRetriever(@Nullable Context context) { Preconditions.checkNotNull(context, "You cannot start a load on a not yet attached View or a Fragment where getActivity() returns null (which usually occurs when getActivity() is called before the Fragment is attached or after the Fragment is destroyed)."); return get(context).getRequestManagerRetriever(); }
继续看 get(context)
@NonNull public static Glide get(@NonNull Context context) { if (glide == null) { Class var1 = Glide.class; synchronized(Glide.class) { if (glide == null) { checkAndInitializeGlide(context); } } } return glide; }
这里的 Glide get(Context) 是一种双重检测单例模式(DCL),保证了多线程下安全,如果对单例模式还不清楚的可以看我之间写的 单例设计模式详解 ,下面我们看下 checkAndInitializeGlide(context); 它到底做了什么?
private static void checkAndInitializeGlide(@NonNull Context context) { if (isInitializing) { //这里会抛出初始化异常的信息 } else { //是否初始化标志 isInitializing = true; //开始进行初始化 initializeGlide(context); isInitializing = false; } }
继续看 initializeGlide(context);
private static void initializeGlide(@NonNull Context context) { //实例化一个 GlideBuilder 在进行初始化 //GlideBuilder 默认的一些配置信息 initializeGlide(context, new GlideBuilder()); }
继续跟踪
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) { //1\. 拿到应用级别的上下文,这里可以避免内存泄漏,我们实际开发也可以通过这种形式拿上下文。 Context applicationContext = context.getApplicationContext(); //2\. 这里拿到 @GlideModule 标识的注解处理器生成的 GeneratedAppGlideModuleImpl、GeneratedAppGlideModuleFactory ...等等。 GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules(); ..... //3\. 通过注解生成的代码拿到 RequestManagerFactory RequestManagerFactory factory = annotationGeneratedModule != null ? annotationGeneratedModule.getRequestManagerFactory() : null; //4\. 将拿到的工厂添加到 GlideBuilder builder.setRequestManagerFactory(factory); .... //5\. 这里通过 Builder 建造者模式,构建出 Glide 实例对象 Glide glide = builder.build(applicationContext); Iterator var13 = manifestModules.iterator(); //6\. 开始注册组件回调 while(var13.hasNext()) { GlideModule module = (GlideModule)var13.next(); module.registerComponents(applicationContext, glide, glide.registry); } if (annotationGeneratedModule != null) { annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry); } applicationContext.registerComponentCallbacks(glide); //将构建出来的 glide 赋值给 Glide 的静态变量 Glide.glide = glide; }
通过上面的注释,相信大家很容易理解,注意看注释 5 ,这里知道是通过建造者生成的,那么具体内部怎么实现的,我们来看看。
package com.bumptech.glide; /** * A builder class for setting default structural classes for Glide to use. */ public final class GlideBuilder { //管理线程池 private Engine engine; //对象池(享元模式),这样做避免重复创建对象,对内存开销有一定效果 private BitmapPool bitmapPool; private ArrayPool arrayPool; //GlideExecutor 线程池 private GlideExecutor sourceExecutor; private GlideExecutor diskCacheExecutor; //本地磁盘缓存 private DiskCache.Factory diskCacheFactory; //内存缓存 private MemorySizeCalculator memorySizeCalculator; private MemoryCache memoryCache; private ConnectivityMonitorFactory connectivityMonitorFactory; private int logLevel = Log.INFO; private RequestOptions defaultRequestOptions = new RequestOptions(); @Nullable private RequestManagerFactory requestManagerFactory; private GlideExecutor animationExecutor; private boolean isActiveResourceRetentionAllowed; @Nullable private List<RequestListener<Object>> defaultRequestListeners; private boolean isLoggingRequestOriginsEnabled; //都是一些配置信息,用到了 开闭原则。 .... //开始构建 @NonNull Glide build(@NonNull Context context) { //实例化一个网络请求的线程池 if (sourceExecutor == null) { sourceExecutor = GlideExecutor.newSourceExecutor(); } //实例化一个本地磁盘缓存的线程池 if (diskCacheExecutor == null) { diskCacheExecutor = GlideExecutor.newDiskCacheExecutor(); } //实例化一个加载图片动画的一个线程池 if (animationExecutor == null) { animationExecutor = GlideExecutor.newAnimationExecutor(); } //实例化一个对图片加载到内存的一个计算 if (memorySizeCalculator == null) { memorySizeCalculator = new MemorySizeCalculator.Builder(context).build(); } //实例化一个默认网络连接监控的工厂 if (connectivityMonitorFactory == null) { connectivityMonitorFactory = new DefaultConnectivityMonitorFactory(); } //实例化一个 Bitmap 对象池 if (bitmapPool == null) { int size = memorySizeCalculator.getBitmapPoolSize(); //如果池子里还有可用的,直接加入 最近最少使用的 LruBitmap 容器里 if (size > 0) { bitmapPool = new LruBitmapPool(size); } else { //如果池子已经满了,那么就装在 BitmapPoolAdapter bitmapPool = new BitmapPoolAdapter(); } } //实例化一个数组对象池 if (arrayPool == null) { arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes()); } //资源内存缓存 if (memoryCache == null) { memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize()); } //磁盘缓存的工厂 if (diskCacheFactory == null) { diskCacheFactory = new InternalCacheDiskCacheFactory(context); } //构建执行缓存策略跟线程池的引擎 if (engine == null) { engine = new Engine( memoryCache, diskCacheFactory, diskCacheExecutor, sourceExecutor, GlideExecutor.newUnlimitedSourceExecutor(), GlideExecutor.newAnimationExecutor(), isActiveResourceRetentionAllowed); } if (defaultRequestListeners == null) { defaultRequestListeners = Collections.emptyList(); } else { defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners); } //实例化一个 RequestManagerRetriever 请求管理类 RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(requestManagerFactory); //实例化 Glide 的地方 return new Glide( context, engine, memoryCache, bitmapPool, arrayPool, requestManagerRetriever, connectivityMonitorFactory, logLevel, defaultRequestOptions.lock(), defaultTransitionOptions, defaultRequestListeners, isLoggingRequestOriginsEnabled); } }
通过上面代码跟注释我们可知,这里 builder 主要构建线程池、复用池、缓存策略、执行 Engine ,最后构建 Glide 实例,我们看看 Glide 怎么实例化的,主要看对应的构造函数就行了。
Glide( @NonNull Context context, @NonNull Engine engine, @NonNull MemoryCache memoryCache, @NonNull BitmapPool bitmapPool, @NonNull ArrayPool arrayPool, @NonNull RequestManagerRetriever requestManagerRetriever, @NonNull ConnectivityMonitorFactory connectivityMonitorFactory, int logLevel, @NonNull RequestOptions defaultRequestOptions, @NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions, @NonNull List<RequestListener<Object>> defaultRequestListeners, boolean isLoggingRequestOriginsEnabled) { //将 Builder 构建的线程池,对象池,缓存池保存到 Glide 中 this.engine = engine; this.bitmapPool = bitmapPool; this.arrayPool = arrayPool; this.memoryCache = memoryCache; this.requestManagerRetriever = requestManagerRetriever; this.connectivityMonitorFactory = connectivityMonitorFactory; //拿到 Glide 对应需要的编解码 DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT); bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat); final Resources resources = context.getResources(); registry = new Registry(); registry.register(new DefaultImageHeaderParser()); //忽略一些配置信息 ... //用于显示对应图片的工厂 ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory(); //构建一个 Glide 专属的 上下文 glideContext = new GlideContext( context, arrayPool, registry, imageViewTargetFactory, defaultRequestOptions, defaultTransitionOptions, defaultRequestListeners, engine, isLoggingRequestOriginsEnabled, logLevel); } 复制代码
这里的 GlideContext 其实是 Context 级别的上下文。
public class GlideContext extends ContextWrapper{ ... } 复制代码
到这里我们已经知道了 缓存策略、Glide、GlideContext 怎么构建出来的了,下面我们看怎么拿到 请求管理类
RequestManager
-
RequestManager getRetriever(activity).get(activity);
这里的 get 也有很多重载的函数,我们就看 Activity 参数的重载。
public class RequestManagerRetriever implements Handler.Callback { @NonNull public RequestManager get(@NonNull Context context) { if (context == null) { throw new IllegalArgumentException("You cannot start a load on a null Context"); //如果在主线程中并且不为 Application 级别的 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) { //一直到查找 BaseContext return get(((ContextWrapper) context).getBaseContext()); } } //如果不在主线程中或为 Application 就直接执行 return getApplicationManager(context); } @NonNull public RequestManager get(@NonNull FragmentActivity activity) { .... } @NonNull public RequestManager get(@NonNull Fragment fragment) { .... } //通过 Activity 拿到 RequestManager @SuppressWarnings("deprecation") @NonNull public RequestManager get(@NonNull Activity activity) { //判断当前是否在子线程中请求任务 if (Util.isOnBackgroundThread()) { //通过 Application 级别的 Context 加载 return get(activity.getApplicationContext()); } else { //检查 Activity 是否已经销毁 assertNotDestroyed(activity); //拿到当前 Activity 的 FragmentManager android.app.FragmentManager fm = activity.getFragmentManager(); //主要是生成一个 Fragment 然后绑定一个请求管理 RequestManager return fragmentGet( activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); } } } 复制代码
下面我们看下 fragmentGet 函数实现
private RequestManager fragmentGet(@NonNull Context context, @NonNull android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) { //1\. 在当前的 Acitivty 添加一个 Fragment 用于管理请求的生命周期 RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible); //拿到当前请求的管理类 RequestManager requestManager = current.getRequestManager(); //如果不存在,则创建一个请求管理者保持在当前管理生命周期的 Fragment 中,相当于 2 者进行绑定,避免内存泄漏。 if (requestManager == null) { Glide glide = Glide.get(context); requestManager = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); current.setRequestManager(requestManager); } //返回当前请求的管理者 return requestManager; } 复制代码
通过上面的代码可知,这里用于 Fragment 管理请求的生命周期,那么我们具体来看看 Fragment 怎么添加到 Activity 中。
private RequestManagerFragment getRequestManagerFragment( @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) { //通过 TAG 拿到已经实例化过的 Fragment ,相当于如果同一个 Activity Glide.with..多次,那么就没有必要创建多个。 RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); //如果在当前 Activity 中没有拿到管理请求生命周期的 Fragment ,那么就从缓存中看有没有 if (current == null) { current = pendingRequestManagerFragments.get(fm); //如果缓存也没有得,就直接实例化一个 Fragment if (current == null) { current = new RequestManagerFragment(); current.setParentFragmentHint(parentHint); //如果已经有执行的请求就开始 if (isParentVisible) { current.getGlideLifecycle().onStart(); } //添加到 Map 缓存中 pendingRequestManagerFragments.put(fm, current); //通过当前 Activity 的 FragmentManager 开始提交添加一个 Fragment 容器 fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); //添加到 FragmentManager 成功,发送清理缓存。 handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current; } 复制代码
最后就到了 把请求管理类绑定到 Fragment 中。
private RequestManager fragmentGet(@NonNull Context context, @NonNull android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) { ... //如果不存在,则创建一个请求管理者保持在当前管理生命周期的 Fragment 中,相当于 2 者进行绑定,避免内存泄漏。 if (requestManager == null) { //拿到单例 Glide Glide glide = Glide.get(context); //构建请求管理,current.getGlideLifecycle(),就是 ActivityFragmentLifecycle 后面我们会讲到这个类 requestManager = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); //将构建出来的请求管理绑定在 Fragment 中。 current.setRequestManager(requestManager); } //返回当前请求的管理者 return requestManager; } 复制代码
看下怎么构建请求管理类的
private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() { @NonNull @Override public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) { //实例化 return new RequestManager(glide, lifecycle, requestManagerTreeNode, context); } }; 复制代码
public RequestManager( @NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode treeNode, @NonNull Context context) { this( glide, lifecycle, treeNode, new RequestTracker(), glide.getConnectivityMonitorFactory(), context); } // Our usage is safe here. @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") RequestManager( Glide glide, Lifecycle lifecycle, RequestManagerTreeNode treeNode, RequestTracker requestTracker, ConnectivityMonitorFactory factory, Context context) { this.glide = glide; this.lifecycle = lifecycle; this.treeNode = treeNode; this.requestTracker = requestTracker; this.context = context; connectivityMonitor = factory.build( context.getApplicationContext(), new RequestManagerConnectivityListener(requestTracker)); //这里只要是添加生命周期监听,Fragment 传递过来的 if (Util.isOnBackgroundThread()) { mainHandler.post(addSelfToLifecycle); } else { lifecycle.addListener(this); } //添加网络变化的监听 lifecycle.addListener(connectivityMonitor); defaultRequestListeners = new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners()); setRequestOptions(glide.getGlideContext().getDefaultRequestOptions()); glide.registerRequestManager(this); } 复制代码
到这里请求管理类 RequestManager + Fragment 已经绑定成功了,声明周期监听也设置了。
那他们相互是怎么保证生命周期的传递勒,我们主要看 Fragment 生命周期方法
//这里为什么监控 Fragment 的生命周期勒,其实大家应该也知道 Fragment 是依附在 Activity 的 Activity 的生命周期在 Fragment 中都有,所以监听 Fragment 就行了。 public class RequestManagerFragment extends Fragment { //相当于生命周期回调 private final ActivityFragmentLifecycle lifecycle; .... @Override public void onStart() { super.onStart(); lifecycle.onStart(); } @Override public void onStop() { super.onStop(); lifecycle.onStop(); } @Override public void onDestroy() { super.onDestroy(); lifecycle.onDestroy(); } ... } 复制代码
这里的 lifecycle 是什么,我们在深入看看去
class ActivityFragmentLifecycle implements Lifecycle { private final Set<LifecycleListener> lifecycleListeners = Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>()); private boolean isStarted; private boolean isDestroyed; @Override public void addListener(@NonNull LifecycleListener listener) { lifecycleListeners.add(listener); if (isDestroyed) { listener.onDestroy(); } else if (isStarted) { listener.onStart(); } else { listener.onStop(); } } @Override public void removeListener(@NonNull LifecycleListener listener) { lifecycleListeners.remove(listener); } void onStart() { isStarted = true; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStart(); } } void onStop() { isStarted = false; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStop(); } } void onDestroy() { isDestroyed = true; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onDestroy(); } } } 复制代码
这里知道了吧,它实现的是 Glide 中的 Lifecycle 生命周期接口,注册是在刚刚我们讲解 RequestManagerFactory 工厂中实例化的 RequestManager 然后在构造函数中添加了生命周期回调监听,具体来看下。
public class RequestManager implements LifecycleListener, ModelTypes<RequestBuilder<Drawable>> { ... @Override public synchronized void onStart() { resumeRequests(); targetTracker.onStart(); } @Override public synchronized void onStop() { pauseRequests(); targetTracker.onStop(); } @Override public synchronized void onDestroy() { targetTracker.onDestroy(); for (Target<?> target : targetTracker.getAll()) { clear(target); } targetTracker.clear(); requestTracker.clearRequests(); lifecycle.removeListener(this); lifecycle.removeListener(connectivityMonitor); mainHandler.removeCallbacks(addSelfToLifecycle); glide.unregisterRequestManager(this); } ... } 复制代码
这 3 处回调就是 Fragment 传递过来的,用于实时监听请求的状态。
with 小总结:
根据 with 源码分析,我们知道,Glide.with(Activity) 主要做了 线程池 + 缓存 + 请求管理与生命周期绑定+其它配置初始化的构建,内部的代码其实是很庞大的,处处都是设计模式,如果还有对设计模式不了解的建议翻看下我之前写的设计模式文章。到这里 Glide.with 我们已经分析完了,下面我们看 load 函数主要做了什么?
load
下面我们就来以 load(String url) 网络图片地址为例来讲解 load 过程。
Glide.with(this).load("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3638429004,1717840478&fm=26&gp=0.jpg")
复制代码
还是老规矩,先上一个时序图。
- RequestBuilder : 这是一个通用请求构建类,可以处理通用资源类型的设置选项和启动负载。
load 函数加载相对于比较简单。我们看下具体代码实现
public class RequestManager implements LifecycleListener,
ModelTypes<RequestBuilder<Drawable>> {
.....
public RequestBuilder<Drawable> load(@Nullable String string) {
//这里调用 Drawable 图片加载请求器为其加载
return asDrawable().load(string);
}
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable File file) {
return asDrawable().load(file);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
}
复制代码
可以看到 load 也有很多重载的函数,不得不说是真的很强大啊,只要给一个图片资源那么就能给你加载出来。
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
implements Cloneable, ModelTypes<RequestBuilder<TranscodeType>> {
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
// 描述加载的数据源-这里可以看做是我们刚刚传递进来的 http://xxxx.png
@Nullable private Object model;
// 描述这个请求是否已经添加了加载的数据源
private boolean isModelSet;
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
}
复制代码
好的, 到这里 RequestBuilder 就构建好了, 接下来就等待执行这个请求了, 我们看看它的 RequestBuilder 的 into 方法。
into
终于等到 into 主角了,大家是不是都等不急了,那么现在我们就一起跟着 into 走一趟吧,还是老规矩,先上一个时序图。
跟了 2 小时 into 时序图终于画完了,如果觉得不清晰,可以下载原版 涉及到的类和回调确实太多了,下面就跟着我一起看下代码具体执行流程。
Glide.with(activity).load(http://xxxx.png).into(imageView);
复制代码
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
// 根据 ImageView 布局中的 scaleType 来重构 requestOptions
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
//如果在 xml ImageView 节点中 没有设置 scaleType 那么默认在构造函数中进行了初始化为 mScaleType = ScaleType.FIT_CENTER;
switch (view.getScaleType()) {
.....
case FIT_CENTER:
case FIT_START:
case FIT_END:
//这里用到了克隆(原型设计模式),选择一个 居中合适 显示的方案
requestOptions = requestOptions.clone().optionalFitCenter();
break;
....
}
}
//调用 into 重载函数,创建一个 ViewTarget
return into(
//调用 buildImageViewTarget 构建一个 ImageView 类型的 Target(Bitmap/Drawable)
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
复制代码
根据上面代码和注释可知:
- 先拿到当前 ImageView getScaleType 类型的属性,然后重新 clone 一个进行配置;
- 调用 into 重载继续构建;
我们先来看下 glideContext.buildImageViewTarget 是怎么构建出来 ImageViewTarget 的
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
//调用 工厂模式 根据 transcodeClass 生成出一个对应的 ImageViewTarget
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
复制代码
public class ImageViewTargetFactory {
@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
@NonNull Class<Z> clazz) {
//如果目标的编码类型属于 Bitmap 那么就创建一个 Bitmap 类型的 ImageViewTarget
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
////如果目标的编码类型属于 Drawable 那么就创建一个 Drawable 类型的 ImageViewTarget
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
}
复制代码
上面 生产 Target 的时候注意一下,只要调用了 asBitmap
才会执行生产 BitmapImageViewTarget ,所以这里我们关注 Drawable 类型就行了,我们就先简单看看这个 target 内部怎么实现的,因为最后会讲到这个,先让大家有个印象。
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
public DrawableImageViewTarget(ImageView view) {
super(view);
}
@SuppressWarnings({"unused", "deprecation"})
@Deprecated
public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
super(view, waitForLayout);
}
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
}
复制代码
从上面代码可以知道 DrawableImageViewTarget 继承的是 ImageViewTarget 重写的 setResource 函数,实现了显示 Drawable 图片的逻辑,好了,这里先有个印象就行,最后会讲到怎么调用的。继续 into 重载。
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
//这里的 isModelSet 是在 load 的时候赋值为 true 的,所以不会抛异常
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//为这个 http://xxx.png 生成一个 Glide request 请求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
//相当于拿到上一个请求
Request previous = target.getRequest();
//下面的几行说明是否与上一个请求冲突,一般不用管 直接看下面 else 判断
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
//清理掉目标请求管理
requestManager.clear(target);
//重新为目标设置一个 Glide request 请求
target.setRequest(request);
//最后是调用 RequestManager 的 track 来执行目标的 Glide request 请求
requestManager.track(target, request);
return target;
}
复制代码
上面有 2 点比较重要:
- 为 target buildRequest 构建一个 Glide request 请求;
- 将构建出来的 Request 交于 RequestManager 来执行.
我们就简单的来看下怎么构建的 Request
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
复制代码
继续跟踪
private Request obtainRequest(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
复制代码
最后我们发现是 SingleRequest.obtain
来为我们构建的 Request 请求对象,开始只是初始化一些配置属性,下面我们就来找begin
开始的地方, 先来看下 track
函数执行。
//这里对当前 class 加了一个同步锁避免线程引起的安全性
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
//添加一个目标任务
targetTracker.track(target);
//执行 Glide request
requestTracker.runRequest(request);
}
复制代码
public void runRequest(@NonNull Request request) {
//添加一个请求
requests.add(request);
//是否暂停
if (!isPaused) {
//没有暂停,开始调用 Request begin 执行
request.begin();
} else {
//如果调用了 暂停,清理请求
request.clear();
pendingRequests.add(request);
}
}
复制代码
上面的逻辑是先为 requests
添加一个请求,看看是否是停止状态,如果不是就调用 request.begin();
执行。
这里的 Request
是一个接口,通过之前我们讲到 buildRequest
函数可知 Request
的实现类是 SingleRequest
我们就直接看它的 begin
函数.
@Override
public synchronized void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
//检查外部调用的尺寸是否有效
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
//失败的回调
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
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()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
复制代码
我们直接看 onSizeReady
public synchronized void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
....//都是一些初始化状态,配置属性,我们不用管。
loadStatus =
//加载
engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this,
callbackExecutor);
}
复制代码
继续跟踪下去
public synchronized <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor) {
//拿到缓存或者请求的 key
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//根据 key 拿到活动缓存中的资源
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
//如果 ActiveResources 活动缓存中有就回调出去
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
return null;
}
//尝试从 LruResourceCache 中找寻这个资源
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
//如果内存缓存 Lru 中资源存在回调出去
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
return null;
}
//------------- 走到这里说明活动缓存 跟内存 缓存都没有找到 -----------
//根据 Key 看看缓存中是否正在执行
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
//如果正在执行,把数据回调出去
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
// -------------- 走到这里说明是一个新的任务 ---------------
// -------------- 构建新的请求任务 ---------------
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
//把当前需要执行的 key 添加进缓存
jobs.put(key, engineJob);
//执行任务的回调
engineJob.addCallback(cb, callbackExecutor);
//开始执行。
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
复制代码
通过 engine.load
这个函数里面的逻辑,我们可以总结几点:
- 先构建请求或者缓存 KEY ;
- 根据 KEY 从内存缓存中查找对应的资源数据(ActiveResources(活动缓存,内部是一个 Map 用弱引用持有),LruResourceCache),如果有就回调 对应监听的 onResourceReady 表示数据准备好了。
- 从执行缓存中查找对应 key 的任务
- 如果找到了,就说明已经正在执行了,不用重复执行。
- 没有找到,通过 EngineJob.start 开启一个新的请求任务执行。
下面我们就来看下 engineJob.start
具体执行逻辑:
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
//拿到 Glide 执行的线程池
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
//开始执行
executor.execute(decodeJob);
}
复制代码
通过 DecodeJob
源码得知,它是实现的 Runnable
接口,这里 GlideExecutor 线程池开始执行,就会启动 DecodeJob 的 run 函数,我们跟踪 run 的实现。
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
Runnable,
Comparable<DecodeJob<?>>,
Poolable {
//线程执行调用 run
@Override
public void run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher<?> localFetcher = currentFetcher;
try {
//是否取消了当前请求
if (isCancelled) {
notifyFailed();
return;
}
//执行
runWrapped();
} catch (CallbackException e) {
.....//一些错误回调
}
}
复制代码
跟踪 runWrapped
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//获取资源状态
stage = getNextStage(Stage.INITIALIZE);
//根据当前资源状态,获取资源执行器
currentGenerator = getNextGenerator();
//执行
runGenerators();
break;
...
}
}
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
//如果外部调用配置了资源缓存策略,那么返回 Stage.RESOURCE_CACHE
//否则继续调用 Stage.RESOURCE_CACHE 执行。
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
//如果外部配置了源数据缓存,那么返回 Stage.DATA_CACHE
//否则继续调用 getNextStage(Stage.DATA_CACHE)
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
//如果只能从缓存中获取数据,则直接返回 FINISHED,否则,返回SOURCE。
//意思就是一个新的资源
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
复制代码
通过上面代码可以知道,我们在找资源的执行器,这里由于我们没有在外部配置缓存策略所以,直接从源数据加载,看下面代码。
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
//从资源缓存执行器
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
//源数据磁盘缓存执行器
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
//什么都没有配置,源数据的执行器
case SOURCE:
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
复制代码
//这里我们知道,返回的是 SourceGenerator
源数据执行器。继续下面代码执行
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//判断是否取消,是否开始
//调用 DataFetcherGenerator.startNext() 判断是否是属于开始执行的任务
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
....
}
复制代码
这里我们先看 currentGenerator.startNext()
这句代码,DataFetcherGenerator
是一个抽象类,那么这里执行的实现类是哪一个,可以参考下面一张表格;
资源状态 | 描述 | 资源执行器 |
---|---|---|
Stage.RESOURCE_CACHE | 从磁盘中获取缓存的资源数据。 | ResourceCacheGenerator |
Stage.DATA_CACHE | 从磁盘中获取缓存的源数据。 | DataCacheGenerator |
Stage.SOURCE | 一次新的请求任务 | SourceGenerator |
因为这里我们没有配置缓存,那么直接看 SourceGenerator
@Override
public boolean startNext() {
...
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
//获取一个 ModelLoad 加载器
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//使用加载器中的 fetcher 根据优先级加载数据
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
复制代码
这里我们就看 helper.getLoadData()
获取的是一个什么样的加载器,我们可以先猜一下,因为没有配置任何缓存,所以可以猜得到是 http 请求了,那么是不是猜测的那样的,我们一起来验证下。
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
//从 Glide 注册的 Model 来获取加载器(注册是在 Glide 初始化的时候通过 registry
// .append()添加的)
List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
for (int i = 0, size = modelLoaders.size(); i < size; i++) {
ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
LoadData<?> current =
//开始构建加载器
modelLoader.buildLoadData(model, width, height, options);
//如果架子啊器不为空,那么添加进临时缓存
if (current != null) {
loadData.add(current);
}
}
}
return loadData;
}
复制代码
首先拿到一个加载器的容器,加载器是在 Glide 初始化的时候 通过 Registry.append()
添加的,这里因为我们以网络链接举例的。所以,ModelLoad 的实现类是 HttpGlideUrlLoader
加载器,我们看下它的具体实现
@Override
public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
@NonNull Options options) {
GlideUrl url = model;
if (modelCache != null) {
url = modelCache.get(model, 0, 0);
if (url == null) {
modelCache.put(model, 0, 0, model);
url = model;
}
}
int timeout = options.get(TIMEOUT);
return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
复制代码
这里看到是返回的一个HttpUrlFetcher
给加载器。加载器我们拿到了,现在开始加载,返回到刚刚的源码,请看下面:
class DataCacheGenerator implements DataFetcherGenerator,
DataFetcher.DataCallback<Object> {
//挑重要代码
@Override
public boolean startNext() {
....
while (!started && hasNextModelLoader()) {
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
//通过拿到的加载器,开始加载数据
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
}
复制代码
因为刚刚我们知道了这里拿到的加载器是HttpUrlFetcher
所以我们直接看它的 loadData 实现
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
//http 请求,返回一个 InputStream 输入流
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
//将 InputStream 以回调形式回调出去
callback.onDataReady(result);
} catch (IOException e) {
callback.onLoadFailed(e);
} finally {
...
}
}
复制代码
我们继续看 loadDataWithRedirects
这个函数是怎么生成的一个 InputStream
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
Map<String, String> headers) throws IOException {
if (redirects >= MAXIMUM_REDIRECTS) {
throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
} else {
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new HttpException("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(timeout);
urlConnection.setReadTimeout(timeout);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
urlConnection.setInstanceFollowRedirects(false);
urlConnection.connect();
stream = urlConnection.getInputStream();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (isHttpOk(statusCode)) {
return getStreamForSuccessfulRequest(urlConnection);
}
...//抛的异常我们暂时先不管
}
复制代码
是不是发现了新大陆,终于到了我们熟悉的 Http 请求了,这里是 HttpURLConnection 作为 Glide 底层成网络请求的。请求成功之后直接返回的是一个输入流,最后会通过 onDataReady
回调到 DecodeJob onDataFetcherReady 函数中。我们跟下回调
首先回调到 SourceGenerator
@Override
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
cb.reschedule();
} else {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
复制代码
这里会有 else 因为我们没有配置缓存,继续回调。
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
Runnable,
Comparable<DecodeJob<?>>,
Poolable {
...
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey; //当前返回数据的 key
this.currentData = data; //返回的数据
this.currentFetcher = fetcher; //返回的数据执行器,这里可以理解为 HttpUrlFetcher
this.currentDataSource = dataSource; //数据来源 url
this.currentAttemptingKey = attemptedKey;
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
//解析返回回来的数据
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
...
}
//解析返回的数据
private void decodeFromRetrievedData() {
Resource<R> resource = null;
try {
// 调用 decodeFrom 解析 数据;HttpUrlFetcher , InputStream , currentDataSource
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
//解析完成后,通知下去
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
复制代码
继续跟 decodeFromData 看看怎么解析成 Resource 的
private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data,
DataSource dataSource) throws GlideException {
...
Resource<R> result = decodeFromFetcher(data, dataSource);
....
return result;
} finally {
fetcher.cleanup();
}
}
@SuppressWarnings("unchecked")
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
throws GlideException {
//获取当前数据类的解析器 LoadPath
LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
//通过 LoadPath 解析器来解析数据
return runLoadPath(data, dataSource, path);
}
private <Data, ResourceType> Resource<R> runLoadPath(Data data, DataSource dataSource,
LoadPath<Data, ResourceType, R> path) throws GlideException {
Options options = getOptionsWithHardwareConfig(dataSource);
//因为这里返回的是一个 InputStream 所以 这里拿到的是 InputStreamRewinder
DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
try {
//将解析资源的任务转移到 Load.path 方法中
return path.load(
rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
} finally {
rewinder.cleanup();
}
}
复制代码
上面代码看到,为了解析数据首先构建一个 LoadPath, 然后创建一个 InputStreamRewinder 类型的 DataRewinder, 最终将数据解析的操作放到了 LoadPath.load 方法中 ,接下来看下 LoadPath.load 方法的具体逻辑操作:
public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int width,
int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException {
try {
return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
} finally {
listPool.release(throwables);
}
}
private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder,
@NonNull Options options,
int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback,
List<Throwable> exceptions) throws GlideException {
Resource<Transcode> result = null;
//遍历内部存储的 DecodePath 集合,通过他们来解析数据
for (int i = 0, size = decodePaths.size(); i < size; i++) {
DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
try {
//这里才是真正解析数据的地方
result = path.decode(rewinder, width, height, options, decodeCallback);
} catch (GlideException e) {
...
}
...
return result;
}
复制代码
跟 path.decode
public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
@NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
//调用 decodeResourec 将数据解析成中间资源
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
//解析完数据回调出去
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
//转换资源为目标资源
return transcoder.transcode(transformed, options);
}
复制代码
接着看 decodeResource 怎么解析成中间资源的
@NonNull
private Resource<ResourceType> decodeResource(DataRewinder<DataType> rewinder, int width,
int height, @NonNull Options options) throws GlideException {
...
try {
return decodeResourceWithList(rewinder, width, height, options, exceptions);
} finally {
...
}
}
@NonNull
private Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder, int width,
int height, @NonNull Options options, List<Throwable> exceptions) throws GlideException {
Resource<ResourceType> result = null;
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = decoders.size(); i < size; i++) {
ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
try {
DataType data = rewinder.rewindAndGet();
if (decoder.handles(data, options)) {
data = rewinder.rewindAndGet();
// 调用 ResourceDecoder.decode 解析数据
result = decoder.decode(data, width, height, options);
}
} catch (IOException | RuntimeException | OutOfMemoryError e) {
...
}
return result;
}
复制代码
可以看到数据解析的任务最终是通过 DecodePath 来执行的, 它内部有三个操作
-
deResource 将源数据解析成资源
- 源数据: InputStream
- 中间产物: Bitmap
-
调用 DecodeCallback.onResourceDecoded 处理资源
-
调用 ResourceTranscoder.transcode 将资源转为目标资源
- 目标资源类型: Drawable
通过上面的 decoder.decode 源码可知,它是一个接口,由于我们这里的源数据是 InputStream,所以,它的实现类是 StreamBitmapDecoder ,我们就来看下 它内部的解码过程
@Override
public Resource<Bitmap> decode(@NonNull InputStream source, int width, int height,
@NonNull Options options)
throws IOException {
// Use to fix the mark limit to avoid allocating buffers that fit entire images.
final RecyclableBufferedInputStream bufferedStream;
final boolean ownsBufferedStream;
....
try {
// 根据请求配置来对数据进行采样压缩,获取一个 Resource<Bitmap>
return downsampler.decode(invalidatingStream, width, height, options, callbacks);
} finally {
....
}
}
复制代码
具体怎么采样压缩,我们先暂时不用关注具体实现,现在拿到了一个 Bitmap 数据,我们需要通过回调出去,请看下面代码
public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
@NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
//1\. 调用 decodeResourec 将数据解析成中间资源 Bitmap
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
//2\. 解析完数据回调出去
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
//3\. 转换资源为目标资源 Bitmap to Drawable
return transcoder.transcode(transformed, options);
}
复制代码
只看第二注释里面回调,最后会回调到 DecodeJob
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
Runnable,
Comparable<DecodeJob<?>>,
Poolable {
...
@Override
public Resource<Z> onResourceDecoded(@NonNull Resource<Z> decoded) {
return DecodeJob.this.onResourceDecoded(dataSource, decoded);
}
...
}
复制代码
继续跟
@Synthetic
@NonNull
<Z> Resource<Z> onResourceDecoded(DataSource dataSource,
@NonNull Resource<Z> decoded) {
@SuppressWarnings("unchecked")
//获取资源类型
Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass();
Transformation<Z> appliedTransformation = null;
Resource<Z> transformed = decoded;
//如果不是从磁盘资源中获取需要进行 transform 操作
if (dataSource != DataSource.RESOURCE_DISK_CACHE) {
appliedTransformation = decodeHelper.getTransformation(resourceSubClass);
transformed = appliedTransformation.transform(glideContext, decoded, width, height);
}
...
//构建数据编码的策略
final EncodeStrategy encodeStrategy;
final ResourceEncoder<Z> encoder;
if (decodeHelper.isResourceEncoderAvailable(transformed)) {
encoder = decodeHelper.getResultEncoder(transformed);
encodeStrategy = encoder.getEncodeStrategy(options);
} else {
encoder = null;
encodeStrategy = EncodeStrategy.NONE;
}
//根据编码策略,构建缓存 Key
Resource<Z> result = transformed;
boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey);
if (diskCacheStrategy.isResourceCacheable(isFromAlternateCacheKey, dataSource,
encodeStrategy)) {
if (encoder == null) {
throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass());
}
final Key key;
switch (encodeStrategy) {
case SOURCE:
//源数据 key
key = new DataCacheKey(currentSourceKey, signature);
break;
。。。
}
//初始化编码管理者,用于提交内存缓存
LockedResource<Z> lockedResult = LockedResource.obtain(transformed);
deferredEncodeManager.init(key, encoder, lockedResult);
result = lockedResult;
}
//返回转换后的 Bitmap
return result;
}
复制代码
可以看到 onResourceDecoded 中, 主要是对中间资源做了如下的操作
- 对资源进行了转换操作。比如 Fit_Center,CenterCrop, 这些都是在请求的时候配置的。
- 构建磁盘缓存的 key.
最后就是将 Bitmap 转换成 Drawable 了操作了 ,请看下面代码
public class DecodePath<DataType, ResourceType, Transcode> {
。。。
Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
@NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
//1\. 调用 decodeResourec 将数据解析成中间资源 Bitmap
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
//2\. 解析完数据回调出去
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
//3\. 转换资源为目标资源 Bitmap to Drawable
return transcoder.transcode(transformed, options);
}
。。。
}
复制代码
只看第三步,通过源码可知,ResourceTranscoder 是一个接口,又因为解析完的数据是 Bitmap 所以它的实现类是 BitmapDrawableTranscoder ,最后看下它的 transcode 具体实现
public class BitmapDrawableTranscoder implements ResourceTranscoder<Bitmap, BitmapDrawable> {
@Nullable
@Override
public Resource<BitmapDrawable> transcode(@NonNull Resource<Bitmap> toTranscode,
@NonNull Options options) {
return LazyBitmapDrawableResource.obtain(resources, toTranscode);
}
}
复制代码
具体我们看下 LazyBitmapDrawableResource.obtain
public final class LazyBitmapDrawableResource implements Resource<BitmapDrawable>,
Initializable {
private final Resources resources;
private final Resource<Bitmap> bitmapResource;
@Deprecated
public static LazyBitmapDrawableResource obtain(Context context, Bitmap bitmap) {
return
(LazyBitmapDrawableResource)
obtain(
context.getResources(),
BitmapResource.obtain(bitmap, Glide.get(context).getBitmapPool()));
}
@Deprecated
public static LazyBitmapDrawableResource obtain(Resources resources, BitmapPool bitmapPool,
Bitmap bitmap) {
return
(LazyBitmapDrawableResource) obtain(resources, BitmapResource.obtain(bitmap, bitmapPool));
}
@Nullable
public static Resource<BitmapDrawable> obtain(
@NonNull Resources resources, @Nullable Resource<Bitmap> bitmapResource) {
if (bitmapResource == null) {
return null;
}
return new LazyBitmapDrawableResource(resources, bitmapResource);
}
private LazyBitmapDrawableResource(@NonNull Resources resources,
@NonNull Resource<Bitmap> bitmapResource) {
this.resources = Preconditions.checkNotNull(resources);
this.bitmapResource = Preconditions.checkNotNull(bitmapResource);
}
@NonNull
@Override
public Class<BitmapDrawable> getResourceClass() {
return BitmapDrawable.class;
}
// Get 方法反回了一个 BitmapDrawable 对象
@NonNull
@Override
public BitmapDrawable get() {
return new BitmapDrawable(resources, bitmapResource.get());
}
@Override
public int getSize() {
return bitmapResource.getSize();
}
@Override
public void recycle() {
bitmapResource.recycle();
}
@Override
public void initialize() {
if (bitmapResource instanceof Initializable) {
((Initializable) bitmapResource).initialize();
}
}
}
复制代码
转化也完成了 ,将我们解析到的 bitmap 存放到 LazyBitmapDrawableResource 内部, 然后外界通过 get 方法就可以获取到一个 BitmapDrawable 的对象了。
解析完就到了展示数据了,请看下面代码:
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
Runnable,
Comparable<DecodeJob<?>>,
Poolable {
//解析返回的数据
private void decodeFromRetrievedData() {
Resource<R> resource = null;
try {
//1\. 调用 decodeFrom 解析 数据;HttpUrlFetcher , InputStream , currentDataSource
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
//2\. 解析完成后,通知下去
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
复制代码
注释 1 解析完了数据,现在执行 notifyEncodeAndRelease
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
...
//通知调用层数据已经装备好了
notifyComplete(result, dataSource);
stage = Stage.ENCODE;
try {
//这里就是将资源磁盘缓存
if (deferredEncodeManager.hasResourceToEncode()) {
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
...
}
//完成
onEncodeComplete();
}
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
// 在 DecodeJob 的构建中, 我们知道这个 Callback 是 EngineJob
callback.onResourceReady(resource, dataSource);
}
复制代码
可以看到 DecodeJob.decodeFromRetrievedData 中主要做了几个操作
- 解析返回回来的资源。
- 拿到解析的资源,如果配置了本地缓存,就缓存到磁盘。
- 通知上层资源准备就绪,可以使用了。
我们直接看 EngineJob 的 onResourceReady 回调函数
@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
}
notifyCallbacksOfResult();
}
@Synthetic
void notifyCallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
Key localKey;
EngineResource<?> localResource;
synchronized (this) {
stateVerifier.throwIfRecycled();
if (isCancelled) {
resource.recycle();
release();
return;
} else if (cbs.isEmpty()) {
...
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
copy = cbs.copy();
incrementPendingCallbacks(copy.size() + 1);
localKey = key;
localResource = engineResource;
}
//回调上层 Engine 任务完成了
listener.onEngineJobComplete(this, localKey, localResource);
//遍历资源回调给 ImageViewTarget
for (final ResourceCallbackAndExecutor entry : copy) {
entry.executor.execute(new CallResourceReady(entry.cb));
}
decrementPendingCallbacks();
}
复制代码
通过上面 EngineJob 的 onResourceReady 回调函数 主要做了 2 件事儿
- 通知上层任务完成。
- 回调 ImageViewTarget 用于展示数据。
我们看下 listener.onEngineJobComplete 具体实现
@SuppressWarnings("unchecked")
@Override
public synchronized void onEngineJobComplete(
EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
if (resource != null) {
resource.setResourceListener(key, this);
//收到下游返回回来的资源,添加到活动缓存中
if (resource.isCacheable()) {
activeResources.activate(key, resource);
}
}
jobs.removeIfCurrent(key, engineJob);
}
复制代码
最后通知 ImageViewTarget ,我们看下具体操作:
//遍历资源回调给 ImageViewTarget
for (final ResourceCallbackAndExecutor entry : copy) {
entry.executor.execute(new CallResourceReady(entry.cb));
}
复制代码
private class CallResourceReady implements Runnable {
private final ResourceCallback cb;
CallResourceReady(ResourceCallback cb) {
this.cb = cb;
}
@Override
public void run() {
synchronized (EngineJob.this) {
if (cbs.contains(cb)) {
...
//返回准备好的资源
callCallbackOnResourceReady(cb);
removeCallback(cb);
}
decrementPendingCallbacks();
}
}
}
复制代码
通过代码可以看到 CallResourceReady 实现 Runnable 他们,当 entry.executor.execute 线程池执行的时候就会调用 run ,最后我们继续跟 callCallbackOnResourceReady
@Synthetic
synchronized void callCallbackOnResourceReady(ResourceCallback cb) {
try {
//回调给 SingleRequest
cb.onResourceReady(engineResource, dataSource);
} catch (Throwable t) {
throw new CallbackException(t);
}
}
复制代码
跟下 SingleRequest onResourceReady 回调实现
public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
loadStatus = null;
....
Object received = resource.get();
if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
releaseResource(resource);
...
onLoadFailed(exception);
return;
}
if (!canSetResource()) {
releaseResource(resource);
status = Status.COMPLETE;
return;
}
//当资源准备好的时候
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
...
anyListenerHandledUpdatingTarget |=
targetListener != null
&& targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
//回调给目标 ImageViewTarget 资源准备好了
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
//加载成功
notifyLoadSuccess();
}
复制代码
这一步主要把准备好的资源回调给显示层,看下面代码
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>
implements Transition.ViewAdapter {
...
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
protected abstract void setResource(@Nullable Z resource);
...
}
private void setResourceInternal(@Nullable Z resource) {
//调用 setResource 函数,将资源显示出来
setResource(resource);
...
}
复制代码
在最开始构建的时候,我们知道只有调用 asBitmap 的时候实现类是 BitmapImageViewTarget
,在这里的测试,并没有调用这个函数,所以它的实现类是 DrawableImageViewTarget
,具体看下它内部实现:
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
public DrawableImageViewTarget(ImageView view) {
super(view);
}
// Public API.
@SuppressWarnings({"unused", "deprecation"})
@Deprecated
public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
super(view, waitForLayout);
}
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
}
复制代码
这里看到抽象类中调用了 setResource ,子类实现并调用了 view.setImageDrawable(resource); 图片现在算是真正的显示出来了。到了这里 Glide.with(activity).load(http://xxx.png).into(imageView)
这一个流程算是讲完了。下面我们就来为这整个流程做一个总结吧。
总结
通过这 Glide.with(activity).load(http://xxx.png).into(imageView)
一简短的代码,整个 Glide 图片加载显示的流程我们已经熟悉了,还有看源码不能一行一行的去理解它内部具体实现,我们只要找准一个点,比如 with 那么我们只关注 with 的具体实现,其它什么也不用管。下面就为 Glide 整个流程简单说一下吧:
在阅读的过程中,如果对文章有疑问或者描述错误的地方,希望你的指出。
如有帮助到你,可以点击一波关注、点赞吗?感谢支持!
更多系列教程GitHub白嫖入口:https://github.com/Timdk857/Android-Architecture-knowledge-2-
作者:DevYK
链接:https://juejin.im/post/5d89e9c051882509662c5620