Glide系列之——Glide对象创建及功能扩展

前言

Glide是一个优秀的开源图片加载组件,广泛应用在各大App当中,并且也是Google官方强力推荐的一个图片加载库,根据官方文档介绍

Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的Api是如此的灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。虽然Glide 的主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求。

可以看出,Glide功能是非常强大的。这么优秀的开源组件,肯定是非常值得学习的。

本系列主要是分为以下几个部分:

1、Glide系列之——初识Glide

2、Glide系列之——Glide对象创建及功能扩展

3、Glide系列之——Glide的Request执行流程及回调

4、Glide系列之——Glide缓存机制

5、Glide系列之——图片变换功能Transformation

这篇文章为第二篇:Glide系列之——Glide对象创建及功能扩展

Glide功能扩展

首先来看下Glide的功能扩展

@GlideModule

通过Glide的使用方式就可以发现Glide是一个全局的对象,在上一篇文章当中,讲到了RequestManagerRetriever对象的获取方式:

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

可以看出Glide对象的获取方式是通过Glide.get(context)方法来获取的,来看下这个get方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private static volatile Glide glide;

/**
* Get the singleton.
*
* @return the singleton
*/
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}

return glide;
}

可以看出是使用double-check的单例方式来获取Glide对象的。在对象创建的时候,首先会通过getAnnotationGeneratedGlideModules方法获取到一个GeneratedAppGlideModule对象,我们先来看下这个getAnnotationGeneratedGlideModules方法:

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
private static GeneratedAppGlideModule getAnnotationGeneratedGlideModules(Context context) {
GeneratedAppGlideModule result = null;
try {
Class<GeneratedAppGlideModule> clazz =
(Class<GeneratedAppGlideModule>)
Class.forName("com.bumptech.glide.GeneratedAppGlideModuleImpl");
result =
clazz.getDeclaredConstructor(Context.class).newInstance(context.getApplicationContext());
} 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;
}

以上代码就非常简单了,就是通过反射创建一个GeneratedAppGlideModuleImpl对象,然后强转为GeneratedAppGlideModule类型,说明这个GeneratedAppGlideModuleImpl肯定是继承自GeneratedAppGlideModule的。到这里,很自然的我们就会去看下这个GeneratedAppGlideModuleImpl到底是个什么东东。你会发现,根本找不到GeneratedAppGlideModuleImpl这个类!那么这个类是什么时候才会生成呢?

有一定经验的同学肯定会猜想应该是使用了编译时注解或者自定义plugin在编译的时候自动生成的。没错,就是使用编译时注解自动生成的,生成方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@GlideModule
public class MyGlideModule extends AppGlideModule {

@Override
public void applyOptions(@NonNull Context context,
@NonNull GlideBuilder builder) {
super.applyOptions(context, builder);
//内存缓存相关,默认是24m
int memoryCacheSizeBytes = 1024 * 1024 * 20; // 20mb
builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));
}

@Override
public boolean isManifestParsingEnabled() {
return false;
}

@Override
public void registerComponents(@NonNull @NotNull Context context,
@NonNull @NotNull Glide glide,
@NonNull @NotNull Registry registry) {
super.registerComponents(context, glide, registry);
}
}

自定义MyGlideModule继承自AppGlideModule,并且给MyGlideModule打上@GlideModule注解,这样在编译的时候就会自动生成GeneratedAppGlideModuleImpl:
glide_aop
来看下GeneratedAppGlideModuleImpl这个类:

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
package com.bumptech.glide;

import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import com.easyliu.demo.glide_demo.MyGlideModule;
import java.util.Collections;
import java.util.Set;

@SuppressWarnings("deprecation")
final class GeneratedAppGlideModuleImpl extends GeneratedAppGlideModule {
private final MyGlideModule appGlideModule;

public GeneratedAppGlideModuleImpl(Context context) {
appGlideModule = new MyGlideModule();
if (Log.isLoggable("Glide", Log.DEBUG)) {
Log.d("Glide", "Discovered AppGlideModule from annotation: com.easyliu.demo.glide_demo.MyGlideModule");
}
}

@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();
}
}

可以看出这个类里面就是使用代理的方式调用了我们自定义的类MyGlideModule的相应的方法。

通过自定义AppGlideModule,我们可以通过GlideBuilder做很多定制化的操作,比如在MyGlideModule里面我们就把内存缓存设置为了20MB,默认是24MB的。

在MyGlideModule里面我们还覆写了isManifestParsingEnabled方法,返回false。这个方法是用来干嘛的呢?

目前我们分析的Glide源码是基于v4版本的,在Glide的v3版本的时候,并不是使用编译时注解来扩展Glide功能的,而是通过在Manifest里面添加meta-data来实现的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Deprecated
public interface GlideModule extends RegistersComponents, AppliesOptions {}

//自定义类继承自GlideModule
public class FlickrGlideModule implements GlideModule {
{@literal @}Override
public void applyOptions(Context context, GlideBuilder builder) {
builder.setDecodeFormat(DecodeFormat.ALWAYS_ARGB_8888);
}
{@literal @}Override
public void registerComponents(Context context, Glide glide) {
glide.register(Model.class, Data.class, new MyModelLoader());
}
}

//Manifest:
<meta-data
android:name="com.bumptech.glide.samples.flickr.FlickrGlideModule"
android:value="GlideModule" />

因此这个isManifestParsingEnabled是V4版本为了兼容v3版本做的处理,后续Glide继续更新的话,对应这些兼容逻辑估计会去掉的。

GlideExtension

我们发现编译时注解在自动生成GeneratedAppGlideModuleImpl的同时,也自动生成了一些其他的类,比如GlideApp、GlideOptions等,如下所示:
generated_api

生成这些类是干嘛的呢?根据官方文档使用-generated-api说明,这个GlideApp其实就是Generated API,用于扩展Glide的功能,为啥叫GlideApp这个名字呢?这个名字其实就是注解GlideModule里面的默认值,自定义的时候可以自行修改即可:

1
2
3
4
5
6
7
8
9
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface GlideModule {
/**
* Returns the name of the class that will be used as a replacement for {@code
* com.bumptech.glide.Glide} in Applications that depend on Glide's generated code.
*/
String glideName() default "GlideApp";
}

GlideApp使用方式如下:

1
2
3
4
5
GlideApp.with(fragment)
.load(myUrl)
.placeholder(R.drawable.placeholder)
.fitCenter()
.into(imageView);

到这里大家肯定心想,这个跟直接使用Glide.with有啥区别啊?为啥要来这一出呢?

刚刚我们也说了,这个GlideApp是用于扩展Glide的功能的,那么具体怎么扩展呢?来看下如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@GlideExtension
public class MyAppGlideExtension {
// Size of mini thumb in pixels.
private static final int MINI_THUMB_SIZE = 100;

private MyAppGlideExtension() {
}

@NonNull
@GlideOption
public static BaseRequestOptions<?> miniThumb(BaseRequestOptions<?> options) {
return options
.fitCenter()
.override(MINI_THUMB_SIZE);
}
}

自定义一个类MyAppGlideExtension,打上GlideExtension注解,给里面的静态方法miniThumb打上一个GlideOption注解,然后我们来编译一下代码,就会发现GlideOptions类里面多了如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @see MyAppGlideExtension#miniThumb(BaseRequestOptions)
*/
@SuppressWarnings("unchecked")
@CheckResult
@NonNull
public GlideOptions miniThumb() {
return (GlideOptions) MyAppGlideExtension.miniThumb(this);
}

/**
* @see MyAppGlideExtension#miniThumb(BaseRequestOptions)
*/
@CheckResult
public static GlideOptions miniThumbOf() {
return new GlideOptions().miniThumb();
}

使用方式如下:

1
2
3
4
GlideApp.with(fragment)
.load(url)
.miniThumb(thumbnailSize)
.into(imageView);

到这里大家就明白是怎么回事了:

1、@GlideExtension注解用于标识一个扩展Glide API的类。注意:被 @GlideExtension 注解的类应以工具类的思维编写。这种类应该有一个私有的、空的构造方法,应为 final 类型,并且仅包含静态方法。被注解的类可以含有静态变量,可以引用其他的类或对象

2、使用@GlideOption注解为RequestOptions添加一个自定义的选项

3、通过自动生成的GlideApp来使用自定义的RequestOptions,从而达到扩展Glide功能的目的

4、还支持使用@GlideType注解添加对新的资源类型的支持(GIF,SVG 等等),使用方式参考:使用-generated-api

以上就是Glide v4 功能扩展的实现原理,使用编译时注解的方式实现的。关于Processor的具体实现,参考github上Glide的源代码。

Glide对象创建

回到最开始,得到annotationGeneratedModule之后,就会调用checkAndInitializeGlide方法:

1
2
3
4
5
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}

在这个方法会对Glide对象进行初始化,来看下这个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@GuardedBy("Glide.class")
private static void checkAndInitializeGlide(
@NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
// 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, generatedAppGlideModule);
isInitializing = false;
}

这个方法里面会进一步调用initializeGlide方法:

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
@GuardedBy("Glide.class")
@SuppressWarnings("deprecation")
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();
//没有读取到annotationGeneratedModule或者允许解析Manifest
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
//解析manifest,获取到GlideModule列表
manifestModules = new ManifestParser(applicationContext).parse();
}

//以下逻辑主要是从manifestModules里面剔除不包括在内的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());
}
}

RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory()
: null;
builder.setRequestManagerFactory(factory);
// 调用GlideModule的applyOptions方法给GlideBuilder设置相关参数
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
// 调用annotationGeneratedModule的applyOptions方法给GlideBuilder设置相关参数
if (annotationGeneratedModule != null) {
annotationGeneratedModule.applyOptions(applicationContext, builder);
}
//调用GlideBuilder.build方法创建Glide对象
Glide glide = builder.build(applicationContext);
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);
}
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
//注册Application的ComponentCallback回调
applicationContext.registerComponentCallbacks(glide);
//最终给单例对象进行赋值
Glide.glide = glide;
}

可以看出,Glide对象创建过程主要是传入GlideBuilder以及GeneratedAppGlideModule,通过调用GeneratedAppGlideModule的相关方法进行Glide功能扩展,在中间也对v3版本进行了兼容性处理,在最后还注册了Application的ComponentCallback回调,注册这个回调是用来干嘛的呢?

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
public class Glide implements ComponentCallbacks2 {

@Override
public void onTrimMemory(int level) {
trimMemory(level);
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
// Do nothing.
}

@Override
public void onLowMemory() {
clearMemory();
}

/**
* Clears as much memory as possible.
*
* @see android.content.ComponentCallbacks#onLowMemory()
* @see android.content.ComponentCallbacks2#onLowMemory()
*/
public void clearMemory() {
// Engine asserts this anyway when removing resources, fail faster and consistently
Util.assertMainThread();
// memory cache needs to be cleared before bitmap pool to clear re-pooled Bitmaps too. See #687.
memoryCache.clearMemory();
bitmapPool.clearMemory();
arrayPool.clearMemory();
}

/**
* Clears some memory with the exact amount depending on the given level.
*
* @see android.content.ComponentCallbacks2#onTrimMemory(int)
*/
public void trimMemory(int level) {
// Engine asserts this anyway when removing resources, fail faster and consistently
Util.assertMainThread();
// Request managers need to be trimmed before the caches and pools, in order for the latter to
// have the most benefit.
for (RequestManager manager : managers) {
manager.onTrimMemory(level);
}
// memory cache needs to be trimmed before bitmap pool to trim re-pooled Bitmaps too. See #687.
memoryCache.trimMemory(level);
bitmapPool.trimMemory(level);
arrayPool.trimMemory(level);
}

可以看出,Glide在接收到TriMemory以及lowMemory回调的时候会做一些内存清理操作,降低内存的消耗,这个思想是值得借鉴的。

总结

这篇文章主要对Glide功能扩展及Glide对象创建进行了简要分析。通过这篇文章相信大家对Glide的扩展功能以及对其对象创建过程有了一定的了解,欢迎继续学习:Glide系列之——Glide的Request执行流程及回调

本篇文章到此就结束了,感谢耐心阅读,不对之处,敬请指出~