深入分析Glide源码
Posted 薛瑄
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入分析Glide源码相关的知识,希望对你有一定的参考价值。
前言
最近研究了一下Glide源码,发现很多地方写的真的很精妙,值得细细品味。Glide 功能丰富,图片三级缓存、可深度定制(继承AppGlideModule、LibraryGlideModule实现更多功能)、修改网络请求库、支持多种输入输出资源的转换(例如输入Stream,输出bitmap等等)、生命周期的管理
虽然下面分析完了,整体的流程,但是想要真正领会设计思想,还需要好好沉淀一下。文章篇幅比较长,但逻辑并不复杂
一、基本使用流程
Glide最基本的使用流程就是下面这行代码,其它所有扩展的额外功能都是以其建造者链式调用的基础上增加的。
Glide.with(context).load(url).into(iv);
或
GlideApp.with(context).load(url).into(iv);
其中的GlideApp是注解处理器自动生成的,要使用GlideApp,必须先配置应用的AppGlideModule模块,里面可以为空配置,也可以根据实际情况添加指定配置。
@GlideModule
public class MyAppGlideModule extends AppGlideModule
@Override
public void applyOptions(Context context, GlideBuilder builder)
// 通过builder 参数,可以配置一些Glide的参数,例如缓存大小、MemoryCache、DiskCache、各种Executor 等等,
//具体可以GlideBuilder的方法
@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide,
@NonNull Registry registry)
// 通过参数registry,可以注册 ModelLoader(数据加载) 、Encoder(写入数据)、Decoder()
当我们启用了 @GlideModule 注解之后会在编译期间生成 GeneratedAppGlideModuleImpl。从下面的代码中可以看出,它实际上就是对我们自定义的 MyAppGlideModule 做了一层包装。这么去做的目的就是它可以通过反射来寻找 GeneratedAppGlideModuleImpl,并通过调用 GeneratedAppGlideModuleImpl 的方法来间接调用我们的 MyAppGlideModule。本质上是一种代理模式的应用:
这个类的路径是在 /build/generated/source/apt/debug/com/bumptech/glide/GeneratedAppGlideModuleImpl.java
final class GeneratedAppGlideModuleImpl extends GeneratedAppGlideModule
private final MyAppGlideModule appGlideModule;
GeneratedAppGlideModuleImpl()
appGlideModule = new MyAppGlideModule();
if (Log.isLoggable("Glide", Log.DEBUG))
Log.d("Glide", "Discovered AppGlideModule from annotation: com.bumptech.glide.samples.gallery.GalleryModule");
@Override
public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder)
appGlideModule.applyOptions(context, builder);
@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide,
@NonNull Registry registry)
appGlideModule.registerComponents(context, glide, registry);
@Override
public boolean isManifestParsingEnabled()
return appGlideModule.isManifestParsingEnabled();
@Override
@NonNull
public Set<Class<?>> getExcludedModuleClasses()
return Collections.emptySet();
@Override
@NonNull
GeneratedRequestManagerFactory getRequestManagerFactory()
return new GeneratedRequestManagerFactory();
现在看这些类,可能有点不知所云,可以先不理会,知道在继承AppGlideModule,可以做一些自定义的事情,具体是哪些事情,看完下面的源码分析后,会清晰明了。
下面源码,会省略部分的代码(例如,进行检查之类的代码),只体现整体的逻辑
借鉴一张艽野尘梦绘制的Glide框架图,让我们对Glide的总体框架有一个初步的了解
二、Glide.with()源码详解
GlideApp.with
也是调用了Glide.with
,先从下图看一下with的整体流程
关于with 的函数,一共有六个多态函数,下面选取三种,作为重点分析,其它类似
1、Glide#with
代码一 类Glide.java
public static RequestManager with(@NonNull Context context)
return getRetriever(context).get(context);
public static RequestManager with(@NonNull Activity activity)
return getRetriever(activity).get(activity);
public static RequestManager with(@NonNull Fragment fragment)
return getRetriever(fragment.getActivity()).get(fragment);
2、Glide#getRetriever
代码二 类Glide.java
private static RequestManagerRetriever getRetriever(@Nullable Context context)
//get 函数中创建了Glide单例
//这里重点介绍get()函数,
//getRequestManagerRetriever() 函数就是返回变量requestManagerRetriever,该变量在创建Glide 时赋值(代码5)
return Glide.get(context).getRequestManagerRetriever();
public static Glide get(@NonNull Context context)
//经典的单例,double check 创建单例,不用多说
if (glide == null)
synchronized (Glide.class)
if (glide == null)
checkAndInitializeGlide(context);
return glide;
private static void checkAndInitializeGlide(@NonNull Context context)
//初始化Glide
initializeGlide(context);
private static void initializeGlide(@NonNull Context context)
//这里创建了一个GlideBuilder,还记得自定义GlideModule时 实现applyOptions函数,其中的GlideBuilder参数吗?
//没错,就是这里创建的
initializeGlide(context, new GlideBuilder());
3、Glide#initializeGlide
代码三 类Glide.java
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder)
Context applicationContext = context.getApplicationContext();
//通过反射找到GeneratedAppGlideModuleImpl 类,如果能找到,就说明自定义了GlideModule
//那么就需要在合适的地方调用applyOptions、registerComponents 来实现自定义的功能
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled())
// 从androidManifest.xml 获取自定义的GlideModule(这是另外一种自定义GlideModule的方式)
manifestModules = new ManifestParser(applicationContext).parse();
//如果在注解中指明了要排除的GlideModule,则把GlideModule删除,在GlideModule中 从AndroidManifest.xml 中获取的
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();
// 获取工厂,用于创建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,代码4分析
Glide glide = builder.build(applicationContext);
//下面registerComponents 方法的执行,需要传递Registry对象,而该对象是在创建Glide 的时候,被赋值,并设置一系列的参数
//执行用户在 manifest 中配置的 GlideModule 接口中的registerComponents 方法
for (com.bumptech.glide.module.GlideModule module : manifestModules)
module.registerComponents(applicationContext, glide, glide.registry);
//执行 使用注解配置的GlideModule 接口中的registerComponents 方法
if (annotationGeneratedModule != null)
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
applicationContext.registerComponentCallbacks(glide);
//向单例赋值
Glide.glide = glide;
4、GlideBuilder#build
代码四 类GlideBuilder.java
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();
//创建数组池
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);
//代码2 getRetriever() 返回的就是该对象
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
//创建Glide
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled);
终于到了真正创建Glide的地方
5、Glide#Glide
代码五 类Glide.java
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)
this.engine = engine;
this.bitmapPool = bitmapPool;
this.arrayPool = arrayPool;
this.memoryCache = memoryCache;
this.requestManagerRetriever = requestManagerRetriever;
this.connectivityMonitorFactory = connectivityMonitorFactory;
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());
...省略若干代码,创建需要加入到registry 的类...
ContentResolver contentResolver = context.getContentResolver();
//添加各种Encoder(把数据存为File)、ResourceDecoder(把数据从类型A转为类型B)、
//ModelLoaderFactory(用于创建ModelLoader,它用于将任意复杂的数据模型转换为可由 DataFetcher 获取模型所代表的资源数据的具体数据类型。用来加载资源的。 )
registry
.append(ByteBuffer.class, new ByteBufferEncoder())
...省略若干代码...
.append(Drawable.class, Drawable.class, new UnitDrawableDecoder())
/* Transcoders */
.register(
Bitmap.class,
BitmapDrawable.class,
new BitmapDrawableTranscoder(resources))
.register(Bitmap.class, byte[].class, bitmapBytesTranscoder)
.register(
Drawable.class,
byte[].class,
new DrawableBytesTranscoder(
bitmapPool, bitmapBytesTranscoder, gifDrawableBytesTranscoder))
.register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);
//该工厂用于生产ImageViewTarget,最终通过ImageViewTarget对象把图片addView到界面上
ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
glideContext =
new GlideContext(
context,
arrayPool,
registry,
imageViewTargetFactory,
defaultRequestOptions,
defaultTransitionOptions,
defaultRequestListeners,
engine,
isLoggingRequestOriginsEnabled,
logLevel);
可以看到,代码主要就是Registry 对象,调用append,register 函数设置一些参数。这些参数,主要作用就是对后面的图片解析、加载
这些参数是设置到Registry 类中成员变量中,下面介绍几个主要的变量
this.modelLoaderRegistry = new ModelLoaderRegistry(throwableListPool);
modelLoaderRegistry 中保存的是 ModelLoaderFactory,它是用来创建ModelLoader的
ModelLoader
它的作用是将任意复杂的数据模型转换为可由 DataFetcher 用于获取模型所代表的资源数据的具体数据类型。叫他加载器比较合适,用来加载资源的。
除此之外,还允许将图片按照 ImageView 大小按需加载。防止浪费内存。
Glide 初始化时会注册很多个 ModelLoader ,除了在创建Glide时 通过registry 注册的,还会注册那些 用户在 manifest 中配置的 ModelLoader
ModelLoader 中有两个方法以及一个内部类:LoadData,下来看看这两个方法:
@Nullable
LoadData<Data> buildLoadData(@NonNull Model model, int width, int height,
@NonNull Options options);
boolean handles(@NonNull Model model);
-
buildLoadData 方法构建一个 LoadData 实例,除了包含 Model 之外还有宽高以及 Option,加载图片时可以根据需要的宽高以及其他设置做到按需加载。
-
handles 方法比较简单,就是用来判断给定模型是不是此加载器可能加载的已识别类型。
LoadData
ModelLoader的内部类 LoadData ,主要作用就是装了三个东西:
- 用于识别资源唯一性的 Key;
- 缓存相关的备用 Key 列表
- DataFetcher
其中 DataFetcher最重要,加载资源的根源就在这里,例如发起网络请求等等,都在这个里面。
this.decoderRegistry = new ResourceDecoderRegistry();
this.resourceEncoderRegistry = new ResourceEncoderRegistry();
decoderRegistry 保存的是ResourceDecoder对象
ResourceDecoder
ResourceDecoder的作用是将ModelLoader加载出来的数据,进行解码,解码成Bitmap,或者BitmapDrawable之类的。Glide中常用的Decoder有两个,其他都是将这两个Decoder进行包装,它们分别是ByteBufferBitmapDecoder和StreamBitmapDecoder。
this.dataRewinderRegistry = new DataRewinderRegistry();
dataRewinderRegistry 中保存的是DataRewinder
DataRewinder
Rewinder担任的是ModelLoader到ResourceDecoder的桥梁的角色,DecodeJob将ModelLoader获得的数据,构造出DataRewinder,然后使用Rewinder将数据传给ResourceDecoder进行解码。
this.encoderRegistry = new EncoderRegistry();
encoderRegistry 中保存的是 Encoder对象
Encoder
Encoder的作用是将数据转换成文件,用来配合Glide硬盘缓存。所以Encoder的相关类,都是转为File类型的
此时Glide 已经创建好了,接下来回到代码一 ,执行get操作,在RequestManagerRetriever 中创建RequestManager
6、RequestManagerRetriever#get
代码六 在RequestManagerRetriever 类中
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))
//在主线程,且context 不是Application类型的
//在满足这个条件下的,都是需要创建一个Fragment ,来关联生命周期的,创建Fragment的过程就不陈述了,都比较简单
if (context 以上是关于深入分析Glide源码的主要内容,如果未能解决你的问题,请参考以下文章
Android:深入剖析图片加载库Glide缓存功能(源码分析)