大家应该都听说过Glide图片加载库,或多或少都知道怎么去使用Glide去加载一张图片。Glide对于使用者来说是非常友好的一个库。那么今天我们就来学习Glide的源码,网上也有很有优秀的博客讲解Glide的源码的,现在我们一起来学习Glide的源码。这个优秀的框架是怎么帮助我们实现图片的加载和显示的。很多人看源码都不知道从哪里下手。这篇博客也分享一下我平时是怎么看源码的。这是基于Glide:4.10
版本的源码分析
首先我们平时是怎么使用Glide的?
Glide.with(context).load(url).into(iv);
这就是平时使用Glide的代码,那么看源码也很简单,就直接从这一段代码开始看,这段代码有三个部分,这三个部分分别是with,load和into。我们这个分析源码也一步一步分析这三个步骤。下面就来看看with,load,into分别做了什么。
Glide.with(context)
//Glide#with(表示某个类的某个方法)
//注意这里返回值是RequestManager,为什么要注意这个,因为后面的load是基于这个返回值去调用的
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
我们点进去Glide的源码看一下,看with这个函数,它有很多重载函数,但是他们里面都有一个相同的步骤就是调用getRetriever(context).get(context)
。
那么接下来继续跟下去,因为通过getRetriever(context).get(context)
我们并不知道里面是什么,看源码的话,就是要知道这里面究竟做了什么。这个方法有两个调用,首先先看getRetriever()
Glide#getRetriever
// Glide#getRetriever
@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).");
//执行Glide.get(context).getRequestManagerRetriever()
return Glide.get(context).getRequestManagerRetriever();
}
这个方法也有两个调用,他里面真正重要的是 Glide.get(context)
。因为getRequestManagerRetriever()
只是返回一个RequestManagerRetriever
而已。所以接下来我们要重点关注了就是Glide.get(context)
Glide#get(context)
@NonNull
public static Glide get(@NonNull Context context) {
//这里使用的是双重检查模式的单例模式去创建一个Glide的单例,所以接下来我们需要知道的就是怎么去创建Glide,以及这个过程中间做了什么
if (glide == null) {
//通过反射找到GeneratedAppGlideModuleImpl 类,如果能找到,就说明自定义了GlideModule,那么就需要实现自己的自定义功能。但是这个对于我们的影响并不大,我们可以忽略这个参数,因为我们分析源码整体流程Glide.with(context).load(url).into(iv);是没有使用到这一部分的
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
@GuardedBy("Glide.class")
private static void checkAndInitializeGlide(
@NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
if (isInitializing) {
throw new IllegalStateException(
"You cannot call Glide.get() in registerComponents(),"
+ " use the provided Glide instance instead");
}
isInitializing = true;
initializeGlide(context, generatedAppGlideModule);
isInitializing = false;
}
@GuardedBy("Glide.class")
private static void initializeGlide(
@NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);
}
/**
*这个方法代码看起来很多,但是我们只需要关注对我们有用的代码逻辑即可,
*有人问了什么是有用的代码逻辑?现在我们回想一下我们跟进这一部分的源码的目的是什么?
*是创建Glide单例对不对?所以我们重点关注这一块就好了。其他的代码逻辑是配置一些注解之后Glide的逻辑,所以目前我们不用管这部分逻辑,但是我还是会注释每一部分是做什么的
*/
private static void initializeGlide(
@NonNull Context context,
@NonNull GlideBuilder builder,
@Nullable GeneratedAppGlideModule annotationGeneratedModule) {
Context applicationContext = context.getApplicationContext();
List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
// 从AndroidManifest.xml 获取自定义的GlideModule(这是另外一种自定义GlideModule的方式)
manifestModules = new ManifestParser(applicationContext).parse();
}
// 根据Impl的黑名单,剔除manifest中的GlideModule类
if (annotationGeneratedModule != null
&& !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
Set<Class<?>> excludedModuleClasses = annotationGeneratedModule.getExcludedModuleClasses();
Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
while (iterator.hasNext()) {
com.bumptech.glide.module.GlideModule current = iterator.next();
if (!excludedModuleClasses.contains(current.getClass())) {
continue;
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
}
iterator.remove();
}
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
}
}
// 获取工厂,用于创建RequestManager(该工厂用于,如果with()参数传递的是application)
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory()
: null;
builder.setRequestManagerFactory(factory);
//执行用户在 manifest 中配置的 GlideModule 接口中的方法
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
//执行使用注解配置的GlideModule 接口中的方法
if (annotationGeneratedModule != null) {
annotationGeneratedModule.applyOptions(applicationContext, builder);
}
//创建Glide
Glide glide = builder.build(applicationContext);
//下面registerComponents 方法的执行,需要传递Registry对象,而该对象是在创建Glide 的时候,被赋值,并设置一系列的参数
//执行用户在 manifest 中配置的 GlideModule 接口中的registerComponents 方法
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
try {
module.registerComponents(applicationContext, glide, glide.registry);
} catch (AbstractMethodError e) {
throw new IllegalStateException(
"Attempting to register a Glide v3 module. If you see this, you or one of your"
+ " dependencies may be including Glide v3 even though you're using Glide v4."
+ " You'll need to find and remove (or update) the offending dependency."
+ " The v3 module name is: "
+ module.getClass().getName(),
e);
}
}
//执行 使用注解配置的GlideModule 接口中的registerComponents 方法
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
//向单例赋值
Glide.glide = glide;
}
如果只用Glide.with(context).load(url).into(iv);
其实上面的initializeGlide
方法可以简化成如下:
Glide#initializeGlide(简化)
private static void initializeGlide(
@NonNull Context context,
@NonNull GlideBuilder builder,
@Nullable GeneratedAppGlideModule annotationGeneratedModule) {
Context applicationContext = context.getApplicationContext();
//创建Glide
Glide glide = builder.build(applicationContext);
applicationContext.registerComponentCallbacks(glide);
//向单例赋值
Glide.glide = glide;
}
所以接下来的目的就清晰了就是 builder.build(applicationContext)
是如何创建glide的。builder
是在initializeGlide(context, new GlideBuilder(), generatedAppGlideModule)
的时候,自己创建的一个GlideBuilder
GlideBuilder#build
//GlideBuilder#build
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 池,用于回收LruCache缓存的图片,把图片回收到bitmapPool中,这样下次再创建图片时,可复用该内存,避免连续创建回收内存,造成的内存抖动
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
//一个固定大小的数组池,它使用 LRU 策略驱逐数组,以使池保持在最大字节大小以下。
if (arrayPool == null) {
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
//创建内存缓存
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
//创建磁盘缓存
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
//创建Engine,真正处理request的类,例如发起网络请求图片,从磁盘读取图片等。
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
animationExecutor,
isActiveResourceRetentionAllowed);
}
if (defaultRequestListeners == null) {
defaultRequestListeners = Collections.emptyList();
} else {
defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
}
//创建RequestManagerRetriever 上面分析的getRetriever() 返回的就是该对象
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
//创建Glide
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled,
isImageDecoderEnabledForBitmaps);
}
现在就到了Glide的构造函数了,整一个Glide的构造方法代码很多,这里会精简一下代码,然后介绍各个部分的作用
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 RequestOptionsFactory defaultRequestOptionsFactory,
@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
@NonNull List<RequestListener<Object>> defaultRequestListeners,
boolean isLoggingRequestOriginsEnabled,
boolean isImageDecoderEnabledForBitmaps) {
this.engine = engine;
this.bitmapPool = bitmapPool;
this.arrayPool = arrayPool;
this.memoryCache = memoryCache;
this.requestManagerRetriever = requestManagerRetriever;
this.connectivityMonitorFactory = connectivityMonitorFactory;
this.defaultRequestOptionsFactory = defaultRequestOptionsFactory;
final Resources resources = context.getResources();
registry = new Registry();
registry.register(new DefaultImageHeaderParser());
//...
//这里省略一些代码,下面是创建需要加入register的类,register类很重要,后面分析很多关键代码都会用到register,这里要有一个印象
ContentResolver contentResolver = context.getContentResolver();
//添加各种Encoder(把数据存为File)、ResourceDecoder(把数据从类型A转为类型B)
//ModelLoaderFactory(用于创建ModelLoader,它用于将任意复杂的数据模型转换为可由 DataFetcher 获取模型所代表的资源数据的具体数据类型。用来加载资源的。
//这里省略大量调用register的各种append()与register()方法,添加各种register
registry
.append(...)
.register(...)
...
//该工厂用于生产ImageViewTarget,最终通过ImageViewTarget对象把图片addView到界面上
ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
//创建GlideContext
glideContext =
new GlideContext(
context,
arrayPool,
registry,
imageViewTargetFactory,
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
engine,
isLoggingRequestOriginsEnabled,
logLevel);
}
下面讲解一下Registry 对象,调用append,register 方法的作用。首先设置一些参数。这些参数,主要作用就是对后面的图片解析、加载。
看一下Register的构造函数
Registry#Registry
// Registry#Registry()
public Registry() {
this.modelLoaderRegistry = new ModelLoaderRegistry(throwableListPool);
this.encoderRegistry = new EncoderRegistry();
this.decoderRegistry = new ResourceDecoderRegistry();
this.resourceEncoderRegistry = new ResourceEncoderRegistry();
this.dataRewinderRegistry = new DataRewinderRegistry();
this.transcoderRegistry = new TranscoderRegistry();
this.imageHeaderParserRegistry = new ImageHeaderParserRegistry();
setResourceDecoderBucketPriorityList(
Arrays.asList(BUCKET_GIF, BUCKET_BITMAP, BUCKET_BITMAP_DRAWABLE));
}
this.modelLoaderRegistry
是一个重要的成员变量,它里面有 ModelLoaderFactory
,而ModelLoaderFactory
它是用来创建**ModelLoader
**的。这个ModelLoader
很重要,所以大家要对他有一定的印象。那么ModelLoader是做什么的呢?
ModelLoader
作用:**一个工厂接口,用于将任意复杂的数据模型转换为可由 DataFetcher
用于获取模型所代表的资源数据的具体数据类型。**可以翻译为加载器。
该接口有两个目标: 1. 将特定模型转换为可解码为资源的数据类型。 2. 允许模型与视图的维度相结合以获取特定大小的资源。这样是为了节省空间。就是可以根据ImageView
的大小加载图片
Glide 初始化时会注册很多个 ModelLoader
,除了在创建Glide时 通过registry 注册的,还会注册那些用户在 manifest 中配置的 ModelLoader
。
那么我们来看看modelLoader
里面有什么功能
//ModelLoader里面的方法
//buildLoadData 方法构建一个 LoadData 实例,除了包含 Model 之外还有宽高以及 Option,加载图片时可以根据需要的宽高以及其他设置做到按需加载。
@Nullable
LoadData<Data> buildLoadData(@NonNull Model model, int width, int height,
@NonNull Options options);
//如果给定模型是此加载器可能加载的可识别类型,则返回 true。
boolean handles(@NonNull Model model);
LoadData
是ModelLoader
的内部类 ,主要作用就是装了三个东西:
- 用于识别资源唯一性的 Key;
- 缓存相关的备用 Key 列表
DataFetcher
其中 DataFetcher
最重要,加载资源的根源就在这里,例如发起网络请求等等,都在这个里面。
来看回Register的构造函数里面还有一些参数
this.decoderRegistry = new ResourceDecoderRegistry();//这个是用于解码
this.resourceEncoderRegistry = new ResourceEncoderRegistry();//这个是用于编码
decoderRegistry
保存的是ResourceDecoder
对象
ResourceDecoder与ResourceEecoder
ResourceDecoder
的作用是将ModelLoader
加载出来的数据,进行解码,解码成Bitmap
,或者BitmapDrawable
之类的。Glide中常用的Decoder有两个,其他都是将这两个Decoder进行包装,它们分别是ByteBufferBitmapDecoder
和StreamBitmapDecoder
。ResourceEncoder
的作用正好相反。
DataRewinder
this.dataRewinderRegistry = new DataRewinderRegistry();
dataRewinderRegistry
中保存的是DataRewinder
Rewinder
担任的是ModelLoader
到ResourceDecoder
的桥梁的角色,DecodeJob
将ModelLoader
获得的数据,构造出DataRewinder
,然后使用Rewinder将数据传给ResourceDecoder
进行解码。
Encoder
this.encoderRegistry = new EncoderRegistry();
encoderRegistry
中保存的是 Encoder
对象。Encoder
的作用是将数据转换成文件,用来配合Glide硬盘缓存。所以Encoder
的相关类,都是转为File类型的。
好,这个Registry
的知识点,大家要多看一遍,不并且理清楚他们之间的关系,不然后面讲解会一脸懵逼,不知道哪个类是做什么的。
到这里Register的创建也讲解完了,也就是Glide的创建也讲解完了。那么现在我们应该回到哪一步?很多人看到这已经蒙圈了,接下来的下一步做什么自己不知道了,因为我们看源码的时候很容易跟着跟着就忘记自己一开始是为了看哪个方法而进去的了,这时候会一直回退啊回退。但是如果有博客给你参考一下有不一样了,因为博客整体下来是一个链式的形式,我们可以更加清晰的知道我们下一步做啥,废话说多了。
我们回到Glide.with(context)
方法里面
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
这里面我们是不是只看了getRetriever(context)
里面的代码逻辑,也就是说,还有一部分没有看,既然我们要看Glide.with(context)
我们就看完它。
RequestManagerRetriever#get()
@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());
}
}
return getApplicationManager(context);
}
从这里可以知道get()有很多重载函数,看一下这里的逻辑,这里判断了如果当前线程是后台线程,那么就直接调用getApplicationManager(context)
,然后返回一个RequestManager
RequestManagerRetriever#getApplicationManager(后台线程)
@NonNull
private RequestManager getApplicationManager(@NonNull Context context) {
if (applicationManager == null