…
在标签中加入一个meta-data配置项,其中android:name指定成我们自定义的MyGlideModule的完整路径,android:value必须指定成GlideModule,这个是固定值。
这样的话,我们就将Glide自定义模块的功能完成了,是不是非常简单?现在Glide已经能够识别我们自定义的这个MyGlideModule了,但是在编写具体的功能之前,我们还是按照老规矩阅读一下源码,从源码的层面上来分析一下,Glide到底是如何识别出这个自定义的MyGlideModule的。
自定义模块的原理
========
显然我们已经用惯了Glide.with(context).load(url).into(imageView)这样一行简洁的Glide图片加载语句,但是我们好像从来没有注意过Glide这个类本身的实例。然而事实上,Glide类确实是有创建实例的,只不过是在内部由Glide自动帮我们创建和管理了,对于开发者而言,大多数情况下是不用关心它的,只需要调用它的静态方法就可以了。
那么Glide的实例到底是在哪里创建的呢?我们来看下Glide类中的get()方法的源码,如下所示:
public class Glide {
private static volatile Glide glide;
…
public static Glide get(Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
Context applicationContext = context.getApplicationContext();
List modules = new ManifestParser(applicationContext).parse();
GlideBuilder builder = new GlideBuilder(applicationContext);
for (GlideModule module : modules) {
module.applyOptions(applicationContext, builder);
}
glide = builder.createGlide();
for (GlideModule module : modules) {
module.registerComponents(applicationContext, glide);
}
}
}
}
return glide;
}
…
}
我们来仔细看一下上面这段代码。首先这里使用了一个单例模式来获取Glide对象的实例,可以看到,这是一个非常典型的双重锁模式。然后在第12行,调用ManifestParser的parse()方法去解析AndroidManifest.xml文件中的配置,实际上就是将AndroidManifest中所有值为GlideModule的meta-data配置读取出来,并将相应的自定义模块实例化。由于你可以自定义任意多个模块,因此这里我们将会得到一个GlideModule的List集合。
接下来在第13行创建了一个GlideBuilder对象,并通过一个循环调用了每一个GlideModule的applyOptions()方法,同时也把GlideBuilder对象作为参数传入到这个方法中。而applyOptions()方法就是我们可以加入自己的逻辑的地方了,虽然目前为止我们还没有编写任何逻辑。
再往下的一步就非常关键了,这里调用了GlideBuilder的createGlide()方法,并返回了一个Glide对象。也就是说,Glide对象的实例就是在这里创建的了,那么我们跟到这个方法当中瞧一瞧:
public class GlideBuilder {
private final Context context;
private Engine engine;
private BitmapPool bitmapPool;
private MemoryCache memoryCache;
private ExecutorService sourceService;
private ExecutorService diskCacheService;
private DecodeFormat decodeFormat;
private DiskCache.Factory diskCacheFactory;
…
Glide createGlide() {
if (sourceService == null) {
final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
sourceService = new FifoPriorityThreadPoolExecutor(cores);
}
if (diskCacheService == null) {
diskCacheService = new FifoPriorityThreadPoolExecutor(1);
}
MemorySizeCalculator calculator = new MemorySizeCalculator(context);
if (bitmapPool == null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
int size = calculator.getBitmapPoolSize();
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
if (memoryCache == null) {
memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
}
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
if (engine == null) {
engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
}
if (decodeFormat == null) {
decodeFormat = DecodeFormat.DEFAULT;
}
return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
}
}
这个方法中会创建BitmapPool、MemoryCache、DiskCache、DecodeFormat等对象的实例,并在最后一行创建一个Glide对象的实例,然后将前面创建的这些实例传入到Glide对象当中,以供后续的图片加载操作使用。
但是大家有没有注意到一个细节,createGlide()方法中创建任何对象的时候都做了一个空检查,只有在对象为空的时候才会去创建它的实例。也就是说,如果我们可以在applyOptions()方法中提前就给这些对象初始化并赋值,那么在createGlide()方法中就不会再去重新创建它们的实例了,从而也就实现了更改Glide配置的功能。关于这个功能我们待会儿会进行具体的演示。
现在继续回到Glide的get()方法中,得到了Glide对象的实例之后,接下来又通过一个循环调用了每一个GlideModule的registerComponents()方法,在这里我们可以加入替换Glide的组件的逻辑。
好了,这就是Glide自定义模块的全部工作原理。了解了它的工作原理之后,接下来所有的问题就集中在我们到底如何在applyOptions()和registerComponents()这两个方法中加入具体的逻辑了,下面我们马上就来学习一下。
更改Glide配置
=========
刚才在分析自定义模式工作原理的时候其实就已经提到了,如果想要更改Glide的默认配置,其实只需要在applyOptions()方法中提前将Glide的配置项进行初始化就可以了。那么Glide一共有哪些配置项呢?这里我给大家做了一个列举:
-
setMemoryCache() 用于配置Glide的内存缓存策略,默认配置是LruResourceCache。
-
setBitmapPool() 用于配置Glide的Bitmap缓存池,默认配置是LruBitmapPool。
-
setDiskCache() 用于配置Glide的硬盘缓存策略,默认配置是InternalCacheD