Registry是Glide内部实现的模块挂接中心,它建立了功能需求和实现模块之间的映射关系,使这些模块能够根据需求进行灵活的挂载,模块和模块之间又相互独立互不影响,很好地实现了系统功能的解耦。
在Registry内部,提供了对如下几种类型模块的挂载支持:

/**
* 数据加载模块
*/
private final ModelLoaderRegistry modelLoaderRegistry;
/**
* 编码存储模块,提供将数据持久化存储到磁盘文件中的功能
*/
private final EncoderRegistry encoderRegistry;
/**
* 解码模块,能够将各种类型数据,例如文件、byte数组等数据解码成bitmap或者drawable等资源
*/
private final ResourceDecoderRegistry decoderRegistry;
/**
* 编码存储模块,提供将bitmap或者drawable等资源文件进行持久化存储的功能
*/
private final ResourceEncoderRegistry resourceEncoderRegistry;
/**
* 数据流重定向模块,例如重定向ByteBuffer中的position或者stream中的指针位置等
*/
private final DataRewinderRegistry dataRewinderRegistry;
/**
* 类型转换模块,提供将不同资源类型进行转换的能力,例如将bitmap转成drawable等
*/
private final TranscoderRegistry transcoderRegistry;

Registry其他实现方法都是围绕着这几个数据结构来实现的,包括挂载模块、查询是否有模块能够处理对应的数据类型等。

挂载结构实现分析

Registry中的几个关键的模块Registry的实现结构极为相似,都是在内部包含一个数据类型和模块接口映射的列表,模块接口一般都是泛型接口,以便子类根据自己来实现处理不同数据类型的功能。下面简单分析一下EncoderRegistry来说明,其代码结构如下:

/**
* Contains an unordered list of {@link Encoder}s capable of encoding arbitrary data types.
*/
public class EncoderRegistry {
// TODO: This registry should probably contain a put, rather than a list.
private final List<Entry<?>> encoders = new ArrayList<>();

/**
* 获取能够处理dataClass类型的encoder集合
* @param dataClass
* @return
*/
@SuppressWarnings("unchecked")
@Nullable
public synchronized <T> Encoder<T> getEncoder(Class<T> dataClass) {
for (Entry<?> entry : encoders) {
if (entry.handles(dataClass)) {
return (Encoder<T>) entry.encoder;
}
}
return null;
}

/**
* 挂载一个encoder,这个encoder能够处理的类型为dataClass类型
* @param dataClass
* @param encoder
*/
public synchronized <T> void add(Class<T> dataClass, Encoder<T> encoder) {
encoders.add(new Entry<>(dataClass, encoder));
}

private static final class Entry<T> {
private final Class<T> dataClass;
@Synthetic final Encoder<T> encoder;

public Entry(Class<T> dataClass, Encoder<T> encoder) {
this.dataClass = dataClass;
this.encoder = encoder;
}

public boolean handles(Class<?> dataClass) {
return this.dataClass.isAssignableFrom(dataClass);
}
}
}

EncoderRegistry本身只管理dataClass和Encoder之间的映射关系。Encoder提供具体的编码能力,其接口只声明了一个方法:

/**
* Writes the given data to the given output stream and returns True if the write completed
* successfully and should be committed.
*
* @param data The data to write.
* @param file The File to write the data to.
* @param options The put of options to apply when encoding.
*/
boolean encode(T data, File file, Options options);

表示其主要功能是将指定的数据编码并持久化存储到文件中,例如其中的一个子类实现如下:

/**
* Writes {@link ByteBuffer ByteBuffers} to {@link File Files}.
*/
public class ByteBufferEncoder implements Encoder<ByteBuffer> {
private static final String TAG = "ByteBufferEncoder";

@Override
public boolean encode(ByteBuffer data, File file, Options options) {
boolean success = false;
try {
ByteBufferUtil.toFile(data, file);
success = true;
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to write data", e);
}
}
return success;
}
}

这个子类就将ByteBuffer中的数据直接写入到文件中,它对应能够处理的数据类型(dataClass)指定了就为ByteBuffer类型。
Glide中Registery的这种映射加上泛型接口的实现是其模块可以松耦合地进行挂载的关键,值得好好效仿。

模块注册

Registery的实现为后续Glide根据配置进行调用提供了极大便利,调用的时候只需要根据当前需要处理什么样的数据类型去Registery中取到指定的功能模块就能通过模块实现对应的功能。例如需要取一张图片,只需要根据图片的key和需要的图片类型(bitmap、drawable或者gif等)并结合其宽高和其他option就可以直接从modelLoader中得到最后想要的数据,而其中的各种细节,例如是从哪里取的数据,数据怎么转换成最后需要的类型等细节对于调用者都是透明的。
在Glide类的构造函数中就对这些模块进行了注册:

DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT);
bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);

final Resources resources = context.getResources();

Downsampler downsampler =
new Downsampler(resources.getDisplayMetrics(), bitmapPool, arrayPool);
ByteBufferGifDecoder byteBufferGifDecoder =
new ByteBufferGifDecoder(context, bitmapPool, arrayPool);
registry = new Registry()
.register(ByteBuffer.class, new ByteBufferEncoder())
.register(InputStream.class, new StreamEncoder(arrayPool))
/* Bitmaps */
.append(ByteBuffer.class, Bitmap.class,
new ByteBufferBitmapDecoder(downsampler))
.append(InputStream.class, Bitmap.class,
new StreamBitmapDecoder(downsampler, arrayPool))
.append(ParcelFileDescriptor.class, Bitmap.class, new VideoBitmapDecoder(bitmapPool))
.register(Bitmap.class, new BitmapEncoder())
/* GlideBitmapDrawables */
.append(ByteBuffer.class, BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, bitmapPool,
new ByteBufferBitmapDecoder(downsampler)))
.append(InputStream.class, BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, bitmapPool,
new StreamBitmapDecoder(downsampler, arrayPool)))
.append(ParcelFileDescriptor.class, BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, bitmapPool, new VideoBitmapDecoder(bitmapPool)))
.register(BitmapDrawable.class, new BitmapDrawableEncoder(bitmapPool, new BitmapEncoder()))
/* GIFs */
.prepend(InputStream.class, GifDrawable.class,
new StreamGifDecoder(byteBufferGifDecoder, arrayPool))
.prepend(ByteBuffer.class, GifDrawable.class, byteBufferGifDecoder)
.register(GifDrawable.class, new GifDrawableEncoder())
/* GIF Frames */
.append(GifDecoder.class, GifDecoder.class, new UnitModelLoader.Factory<GifDecoder>())
.append(GifDecoder.class, Bitmap.class, new GifFrameResourceDecoder(bitmapPool))
/* Files */
.register(new ByteBufferRewinder.Factory())
.append(File.class, ByteBuffer.class, new ByteBufferFileLoader.Factory())
.append(File.class, InputStream.class, new FileLoader.StreamFactory())
.append(File.class, File.class, new FileDecoder())
.append(File.class, ParcelFileDescriptor.class, new FileLoader.FileDescriptorFactory())
.append(File.class, File.class, new UnitModelLoader.Factory<File>())
/* Models */
.register(new InputStreamRewinder.Factory(arrayPool))
.append(int.class, InputStream.class, new ResourceLoader.StreamFactory(resources))
.append(
int.class,
ParcelFileDescriptor.class,
new ResourceLoader.FileDescriptorFactory(resources))
.append(Integer.class, InputStream.class, new ResourceLoader.StreamFactory(resources))
.append(
Integer.class,
ParcelFileDescriptor.class,
new ResourceLoader.FileDescriptorFactory(resources))
.append(String.class, InputStream.class, new DataUrlLoader.StreamFactory())
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
.append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
.append(Uri.class, InputStream.class, new AssetUriLoader.StreamFactory(context.getAssets()))
.append(
Uri.class,
ParcelFileDescriptor.class,
new AssetUriLoader.FileDescriptorFactory(context.getAssets()))
.append(Uri.class, InputStream.class, new MediaStoreImageThumbLoader.Factory(context))
.append(Uri.class, InputStream.class, new MediaStoreVideoThumbLoader.Factory(context))
.append(
Uri.class,
InputStream.class,
new UriLoader.StreamFactory(context.getContentResolver()))
.append(Uri.class, ParcelFileDescriptor.class,
new UriLoader.FileDescriptorFactory(context.getContentResolver()))
.append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory())
.append(URL.class, InputStream.class, new UrlLoader.StreamFactory())
.append(Uri.class, File.class, new MediaStoreFileLoader.Factory(context))
.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
.append(byte[].class, ByteBuffer.class, new ByteArrayLoader.ByteBufferFactory())
.append(byte[].class, InputStream.class, new ByteArrayLoader.StreamFactory())
/* Transcoders */
.register(Bitmap.class, BitmapDrawable.class,
new BitmapDrawableTranscoder(resources, bitmapPool))
.register(Bitmap.class, byte[].class, new BitmapBytesTranscoder())
.register(GifDrawable.class, byte[].class, new GifDrawableBytesTranscoder());

从这里我们可以看到Glide的一些基本模块的实现,当然,由于结构设计的灵活性,我们完全可以在使用Glide的时候根据我们自己的使用情况注册我们自己的功能模块,实现功能扩充。

更多相关文章

  1. android studio 解析Excel数据格式导入poi-3.17.jar时的一系列报
  2. 将JSON数据传递到SQLite并检索它
  3. PacketReader 如何实现smack数据监听机制和packet分发机制
  4. 将数据从java类传递到Web View html
  5. 【Android Developers Training】 82. 序言:传输数据时减少对电池
  6. Android中复杂Json数据的解析
  7. 无法从Android中的Asset文件夹复制数据库
  8. 关于activity之间及activity与baseAdapter,activity与Fragment的
  9. Android功能模块化之网络连接状态判断

随机推荐

  1. Android串口Serial服务解析
  2. Android技术专家 高焕堂 推荐这本书
  3. Android音乐播放器系列讲解之一
  4. Android的ps命令介绍和技巧
  5. Android:关于声明文件中android:process
  6. Android 6.0权限机制
  7. Android五大布局详解
  8. Android录屏命令、Android录Gif、Android
  9. 为什么说Android令人沮丧
  10. Android 知识图谱:该如何入门Android开发?