Glide 源码解析 一

前言

在众多的图片加载框架中,Glide 是 Google 推荐的,并在自家的项目中大量使用的一个非常强大的框架,专注于平滑滚动,并且还提供 Gif,本地 Vedio 首帧的解码和显示。Glide 提供了非常便捷的链式调用接口,以及丰富的拓展和自定义功能,开发者可以非常简单地对框架进行配置和图片再加工。

如今 Gilde 已经更新到4.x,了解其源码对更好的使用 Glide ,以及学习相关的图片处理技术,学习更优雅的编码会有很大的帮助。

不得不说,Glide 整个框架的极其复杂的,特别是在对资源的转换和解码过程中,涉及了许多的嵌套循环,同时也使用了大量的工厂模式用于生产转换模块,编码模块,解码模块等,笔者在阅读过程中,多次迷失在茫茫的代码流中。

为此,萌生了将对 Glide 的理解记录成文的想法,借以理清思路。

那么接下来,我们就先看看 Glide 是如何进行框架初始化的。

探究

Glide.with发生了什么?

1. Glide单例的加载

使用过 Glide 的都知道,调用 Glide 加载一张图片时,第一句代码便是 Glide.with(this),这里肯定就是 Glide 的入口了,通过这句代码,Glide 开始了“漫漫的”初始化之路。

Glide 重载了多个 with 的方法,分别用于不同的情境下使用,我们看其中最常用的在 Activity 中调用的方法,即

1
2
3
4
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}

首先,跟进 getRetriever(activity)

1
2
3
4
5
6
7
8
9
10
11
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Context could be null for other reasons (ie the user passes in null), but in practice it will
// only occur due to errors with the Fragment lifecycle.
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 Glide.get(context).getRequestManagerRetriever();
}

这里首先检查了 context 是否为空,如果为 null,抛出异常。

我们重点来看 Glide.get(context)

1
2
3
4
5
6
7
8
9
10
11
12
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}

return glide;
}

这里是一个典型的双检锁单例模式。

继续跟进 checkAndInitialzeGlide(context)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static void checkAndInitializeGlide(@NonNull Context context) {
// In the thread running initGlide(), one or more classes may call Glide.get(context).
// Without this check, those calls could trigger infinite recursion.
if (isInitializing) {
throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
+ " use the provided Glide instance instead");
}
isInitializing = true;
initializeGlide(context);
isInitializing = false;
}

private static void initializeGlide(@NonNull Context context) {
initializeGlide(context, new GlideBuilder());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@SuppressWarnings("deprecation")
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext();
// 获取注解的 module
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
// AndroidMenifest.xml 中注册的 module
manifestModules = new ManifestParser(applicationContext).parse();
}

// 移除相同的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;
}
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());
}
}

RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory() : null;
builder.setRequestManagerFactory(factory);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.applyOptions(applicationContext, builder);
}
Glide glide = builder.build(applicationContext);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.registerComponents(applicationContext, glide, glide.registry);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;
}

留意最后将初始化得到的glide赋值给了Glide.glide的单例。

接下里就来看看在这初始化方法中,Glide都加载了哪些配置。

2. GlideModule配置加载

在使用 Glide 的时候,我们都会有一些想要设置的系统级配置,如设置缓存的存储位置,缓存区的大小,网络加载模块等等,那么我们通常就是使用 GldieModule 进行配置。在 Glide3.x 中,我们首先会定义一个继承于 GlideModule 的类,然后在项目的 AndroidMenifest.xml 中进行指定:

1
2
<meta-data android:name="com.test.GlideConfiguration"
android:value="GlideModule"/>

而在 Glide4 中,提供另外一个配置的模式,那就是注解,并且不再继承 GlideModule ,而是继承 AppGlideModule 和 LibraryGlideModule,分别对应 Application 和 Library,使用 @GlideModule 注解进行标记。而 Glide3.x 中的配置方式已经建议放弃使用。示例如下:

1
2
3
4
5
6
7
8
@GlideModule
public class GlideConfiguration extends AppGlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
//设置缓存到外部存储器
builder.setDiskCache(new ExternalPreferredCacheDiskCacheFactory(context));
}
}

Glide 是如何对 GlideModule 的配置进行初始化的呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Context applicationContext = context.getApplicationContext();
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();

List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
manifestModules = new ManifestParser(applicationContext).parse();
}

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;
}
iterator.remove();
}
}

第二行代码中,getAnnotationGeneratedGlideModules() 会获取 Glide 注解自动生产的一个 Glide 的 Module 配置器。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Nullable
@SuppressWarnings({"unchecked", "deprecation", "TryWithIdenticalCatches"})
private static GeneratedAppGlideModule getAnnotationGeneratedGlideModules() {
GeneratedAppGlideModule result = null;
try {
Class<GeneratedAppGlideModule> clazz =
(Class<GeneratedAppGlideModule>)
Class.forName("com.bumptech.glide.GeneratedAppGlideModuleImpl");
result = clazz.getDeclaredConstructor().newInstance();
} catch (ClassNotFoundException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Failed to find GeneratedAppGlideModule. You should include an"
+ " annotationProcessor compile dependency on com.github.bumptech.glide:compiler"
+ " in your application and a @GlideModule annotated AppGlideModule implementation or"
+ " LibraryGlideModules will be silently ignored");
}
// These exceptions can't be squashed across all versions of Android.
} catch (InstantiationException e) {
throwIncorrectGlideModule(e);
} catch (IllegalAccessException e) {
throwIncorrectGlideModule(e);
} catch (NoSuchMethodException e) {
throwIncorrectGlideModule(e);
} catch (InvocationTargetException e) {
throwIncorrectGlideModule(e);
}
return result;
}

其中 com.bumptech.glide.GeneratedAppGlideModuleImpl 是在编译时由 Glide 生成的一个类,主要用于过滤不必要的 GlideModule ,以及提供一个请求检索器工厂,这个后面会讲到。

接下生成一个 Manifest 解析器 ManifestParser ,用于获取配置的 GlideModule ,并存放在 manifestModules 中。然后是一个判断

1
2
3
4
if (annotationGeneratedModule != null
&& !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
......
}

如果条件成立,即编译时自动生成的类中,包含了需要排除的 GlideModule ,逐个将其移除。

接着以上代码,Glide 将逐个调用剩下的 GlideModule ,并回调 applyOptionsregisterComponents 接口,这时,用户配置的 GlideModule 就会被调用,同时用户设置的参数也就被配置到 Glide 中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory() : null;
builder.setRequestManagerFactory(factory);

// 逐个回调用户配置的 GlideModule
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}

// 回调注释标记的 AppGlideModule
if (annotationGeneratedModule != null) {
annotationGeneratedModule.applyOptions(applicationContext, builder);
}

// 构造 Glide 实例
Glide glide = builder.build(applicationContext);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.registerComponents(applicationContext, glide, glide.registry);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;

在以上代码中,发现一句代码,在回调 registerComponents 前,首先构建了 glide 的实例。

1
Glide glide = builder.build(applicationContext);

3. GlideBuilder构建Glide单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
@NonNull
Glide build(@NonNull Context context) {

/*
* 建立资源加载请求器,实际上是一个线程池,
* 用于加载 URL 或者本地资源,即加载源数据
*/
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}

/*
* 建立本地缓存资源加载请求器,也是一个线程池
* 用于加载缓存在磁盘中的数据
* 并且这个线程池不能用于加载 url 网络数据
*/
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 资源缓存池,
* 该缓存主要用于 bitmap 资源的缓存和回收,
* 避免由于大量创建和回收 bitmap 导致内存抖动
*/
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());
}

/*
* 本地磁盘缓存器,默认为存储在 app 内部私密目录
*/
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}


/*
* 创建图片加载引擎,用于执行图片加载请求驱动
*/
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
}

/*
* 建立请求索引器
*/
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);

/*
* 创建 Glide
*/
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions);
}

通过以上一系列工具的新建,Glide 建立了资源请求线程池,本地缓存加载线程池,动画线程池,内存缓存器,磁盘缓存工具等等,接着构造了 Engine 数据加载引擎,最后再将 Engine 注入 Glide ,构建 Glide 。

其中还建立了一个请求器索引器,用于索引 RequestManger ,后面我们再详细讲。

我们进入最后, 构建 Glide 。

4. 构建Glide,配置数据转换器/解码器/转码器/编码器

回到 Glide 中,看看 Glide 的构造函数,这是一个长得变态的构造函数(有200行),但是不必被它吓倒(好吧,其实第一次看到这里,我是被吓倒了,直接略过去了,限于文章篇幅,这里只截取了部分源码,仔细的话可以直接看源码),仔细分析一下,其实整个构造过程并没那么复杂。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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) {

// 步骤1:赋值 GlideBuilder 注入的工具
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();

// 步骤2:新建注册器
registry = new Registry();
registry.register(new DefaultImageHeaderParser());

// 步骤3:构建编码器和解码器
Downsampler downsampler = new Downsampler(registry.getImageHeaderParsers(),
resources.getDisplayMetrics(), bitmapPool, arrayPool);
ByteBufferGifDecoder byteBufferGifDecoder =
new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), bitmapPool, arrayPool);
ResourceDecoder<ParcelFileDescriptor, Bitmap> parcelFileDescriptorVideoDecoder =
VideoDecoder.parcel(bitmapPool);
ByteBufferBitmapDecoder byteBufferBitmapDecoder = new ByteBufferBitmapDecoder(downsampler);
StreamBitmapDecoder streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool);
ResourceDrawableDecoder resourceDrawableDecoder =
new ResourceDrawableDecoder(context);
ResourceLoader.StreamFactory resourceLoaderStreamFactory =
new ResourceLoader.StreamFactory(resources);
ResourceLoader.UriFactory resourceLoaderUriFactory =
new ResourceLoader.UriFactory(resources);
ResourceLoader.FileDescriptorFactory resourceLoaderFileDescriptorFactory =
new ResourceLoader.FileDescriptorFactory(resources);
ResourceLoader.AssetFileDescriptorFactory resourceLoaderAssetFileDescriptorFactory =
new ResourceLoader.AssetFileDescriptorFactory(resources);
BitmapEncoder bitmapEncoder = new BitmapEncoder(arrayPool);

BitmapBytesTranscoder bitmapBytesTranscoder = new BitmapBytesTranscoder();
GifDrawableBytesTranscoder gifDrawableBytesTranscoder = new GifDrawableBytesTranscoder();

ContentResolver contentResolver = context.getContentResolver();

// 步骤4:开始注册各个类型对应的解码器和编码器 省略部分代码
registry
.append(ByteBuffer.class, new ByteBufferEncoder())
.append(InputStream.class, new StreamEncoder(arrayPool))
/* Bitmaps */
.append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder)
.append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder)
/* BitmapDrawables */
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
ByteBuffer.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, byteBufferBitmapDecoder))
/* GIFs */
.append(
Registry.BUCKET_GIF,
InputStream.class,
GifDrawable.class,
new StreamGifDecoder(registry.getImageHeaderParsers(), byteBufferGifDecoder, arrayPool))
.append(Registry.BUCKET_GIF, ByteBuffer.class, GifDrawable.class, byteBufferGifDecoder)
.append(GifDrawable.class, new GifDrawableEncoder())
/* GIF Frames */
// Compilation with Gradle requires the type to be specified for UnitModelLoader here.
.append(
GifDecoder.class, GifDecoder.class, UnitModelLoader.Factory.<GifDecoder>getInstance())
.append(
Registry.BUCKET_BITMAP,
GifDecoder.class,
Bitmap.class,
new GifFrameResourceDecoder(bitmapPool))
/* Drawables */
.append(Uri.class, Drawable.class, resourceDrawableDecoder)
.append(
Uri.class, Bitmap.class, new ResourceBitmapDecoder(resourceDrawableDecoder, bitmapPool))
/* Files */
.register(new ByteBufferRewinder.Factory())
.append(File.class, ByteBuffer.class, new ByteBufferFileLoader.Factory())

// Compilation with Gradle requires the type to be specified for UnitModelLoader here.
.append(File.class, File.class, UnitModelLoader.Factory.<File>getInstance())
/* Models */
.register(new InputStreamRewinder.Factory(arrayPool))
.append(int.class, InputStream.class, resourceLoaderStreamFactory)

/* Transcoders */
.register(
Bitmap.class,
BitmapDrawable.class,
new BitmapDrawableTranscoder(resources))
.register(Bitmap.class, byte[].class, bitmapBytesTranscoder);


// 步骤5:新建图片显示目标对象工厂,并构建 Glide 上下文
ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
glideContext =
new GlideContext(
context,
arrayPool,
registry,
imageViewTargetFactory,
defaultRequestOptions,
defaultTransitionOptions,
engine,
logLevel);
}

其中最重要的是步骤3和步骤4,分别为 Glide 初始化了模型转换加载器,解码器,转码器,编码器,并将对各种类型进行一一注册,将其列成表格如下:

  • 模型转换器
转换器 功能
ResourceLoader.StreamFactory 将Android资源ID转换为Uri,在加载成为InputStream
ResourceLoader.UriFactory 将资源ID转换为Uri
ResourceLoader.FileDescriptorFactory 将资源ID转化为ParcelFileDescriptor
ResourceLoader.AssetFileDescriptorFactory 将资源ID转化为AssetFileDescriptor
UnitModelLoader.Factory 不做任何转换,返回源数据
ByteBufferFileLoader.Factory 将File转换为ByteBuffer
FileLoader.StreamFactory 将File转换为InputStream
FileLoader.FileDescriptorFactory 将File转化为ParcelFileDescriptor
DataUrlLoader.StreamFactory 将Url转化为InputStream
  • 解码器
解码器 功能
ByteBufferGifDecoder 将ByteBuffer解码为GifDrawable
ByteBufferBitmapDecoder 将ByteBuffer解码为Bitmap
ResourceDrawableDecoder 将资源Uri解码为Drawable
ResourceBitmapDecoder 将资源ID解码为Bitmap
BitmapDrawableDecoder 将数据解码为BitmapDrawable
StreamBitmapDecoder 将InputStreams解码为Bitmap
StreamGifDecoder 将InputStream数据转换为BtyeBuffer,再解码为GifDrawable
GifFrameResourceDecoder 解码gif帧
FileDecoder 包装File成为FileResource
  • 转码器
转码器 功能
BitmapDrawableTranscoder 将Bitmap转码为BitmapDrawable
BitmapBytesTranscoder 将Bitmap转码为Byte arrays
DrawableBytesTranscoder 将BitmapDrawable转码为Byte arrays
GifDrawableBytesTranscoder 将GifDrawable转码为Byte arrays
  • 编码器
编码器 功能
ByteBufferEncoder 将Byte数据缓存为File
StreamEncoder InputStream缓存为File
BitmapEncoder 将Bitmap数据缓存为File
BitmapDrawableEncoder 将BitmapDrawable数据缓存为File
GifDrawableEncoder 将GifDrawable数据缓存为File
  • 模型转换注册表(实在太多,只列出了部分)
源数据 转换数据 转换器
Integer.class InputStream.class ResourceLoader.StreamFactory
String.class InputStream.class DataUrlLoader.StreamFactory
Uri.class InputStream.class DataUrlLoader.StreamFactory

以上模型转换注册表非常重要,在Glide进入解码流程时,将会遍历这里注册的所有可能转换的情形,尝试进行数据转换。

这里只列出部分情形,其它还包括 File/Bitmap/Drawable/Byte 等等几乎涵括了日常使用的情况。

Glide的加载流程可以概括为以下流程:

model(数据源)-->data(转换数据)-->decode(解码)-->transformed(缩放)-->transcoded(转码)-->encoded(编码保存到本地)

其中,transformed 为对解码得到的图片数据进行缩放,如 FitCenter、CropCenter 等。

到这里,Glide 单例就构建完成了,让我们返回到 Glide#with 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}

@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Context could be null for other reasons (ie the user passes in null), but in practice it will
// only occur due to errors with the Fragment lifecycle.
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 Glide.get(context).getRequestManagerRetriever();
}

在构建好 Glide 后,通过 getRequestManagerRetriever() 将会得到一个 RequestManagerRetriever ,即 RequestManager 的检索器,RequestManagerRetriever#get() 将为每个请求页面创建一个 RequestManager。

还记得 GlideBuilder#build 提到的一句代码吗?

1
2
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);

没错,这里获取的就是它。这里就必须要讲到 Glide 数据请求的生命周期了。

我们都知道 Glide 会根据页面的生命周期来自动的开启和结束数据的请求,那么 Glide 是怎么做到的呢?

5. 生命周期管理

我们进入 RequestManagerRetriever#get(Activity) 方法中。

1
2
3
4
5
6
7
8
9
10
11
12
@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();
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}

首先,判断是否为后台线程,如果是,则使用 ApplicationContext 重新获取。
重点来看 else 代码块。先断言请求的页面是否已经销毁。否则获取当前页面的 FragmentManager,并传给 fragmentGet 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"})
@Deprecated
@NonNull
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}

@NonNull
SupportRequestManagerFragment getSupportRequestManagerFragment(FragmentActivity activity) {
return getSupportRequestManagerFragment(
activity.getSupportFragmentManager(), /*parentHint=*/ null, isActivityVisible(activity));
}

在 fragmentGet 中首先通过 getRequestManagerFragment() 来获取一个命名为 FRAGMENT_TAG 的 fragment,如不存在,则新建一个 RequestManagerFragment,并添加到当前页面中。

这里我们就可以猜到了,Glide 是通过在页面中添加一个 Fragment 来动态监听页面的创建和销毁,从而达到依赖页面生命周期,动态管理请求的目的。

在 RequestManagerFragment 构造函数中,注入了一个生命周期监听器 ActivityFragmentLifecycle,并在 Fragment 各个生命周期回调中,调用了对应的方法。

而 ActivityFragmentLifecycle 也紧接着会调用 lifecycleListener 监听器,而这个监听器其实就是 RequestManger。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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();
}
}
}

最后,RequestManagerRetriever#fragmentGet,判断这个Fragment的RequestManager是否存在,否则创建一个RequestManager,并将生命周期注入,同时RquestManager构建时,将会通过addListener注入生命周期回调(具体可以查看RequestManger构造函数)。

最后,Glide#with终将得到一个RequestManager。

至此,Glide的加载过程就解析完毕了。总结一下整个流程:

  • 通过AndroidManifest和@GlideModule注解获取用户自定义配置GlideModule,并调用其对应的方法
  • 通过GlideBuilder构建Glide:
    1. 新建线程池
    2. 新建图片缓存池和缓存池
    3. 新建内存缓存管理器
    4. 新建默认本地缓存管理器
    5. 新建请求引擎Engine
    6. 新建RequestManger检索器
    7. 新建Glide
  • Glide构造方法中,新建模型转换器,解码器,转码器,编码器,以及生成Glide上下文GlideContext
  • 通过RequestManager检索器,建立生命周期监听,并建立一个RequestManager

Glide与GlideApp

如果在项目中已经使用了 Glide3.x ,并且想要升级到 Glide4.x ,那么你会发现,原来使用链式调用进行参数配置的方法已经被修改了,同一个封装到了 RequesOptions 中,如下:

1
2
3
4
5
6
7
8
9
10
RequestOptions options = new RequestOptions()
.centerCrop()
.placeholder(R.mipmap.ic_launcher_round)
.error(R.mipmap.ic_launcher)
.priority(Priority.HIGH)
.diskCacheStrategy(DiskCacheStrategy.NONE);
Glide.with(this)
.load(ImageConfig.URL_GIF)
.apply(options)
.into(iv);

这样的话升级后将导致大量的修改,当然你也可以自己封装一下,但是 Glide 已经为我们做好了兼容方案。

还记得初始化是通过 @GlideModule 注解来注册自定义配置吗?只要在项目中定义这么一个配置,那么 Glide 将会自动帮我们生成一个 GlideApp 模块,封装了 Glide3.x 中的调用方式。

1
2
3
4
5
6
public class GlideConfiguration extends AppGlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {

}
}

调用如下,还是原来的配方,还是熟悉的味道~

1
2
3
4
5
6
7
GlideApp.with(this)
.load(ImageConfig.URL_WEBP)
.sizeMultiplier(0.5f)
.centerCrop()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.error(R.mipmap.ic_launcher)
.into(iv);

如果你还觉得不爽,那么你甚至可以把GlideApp直接修改为Glide,实现几乎“无缝对接”。当然,你还是要修改引用路径的。

1
2
3
4
5
6
7
@GlideModule(glideName="Glide")
public class GlideConfiguration extends AppGlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {

}
}

来源:

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×

keyboard_arrow_up 回到顶端