一、概述
GLide中所有的下载器,解码器,编码器,转换器等都是通过Registry管理的,在生成Registry实例的时候会把内置的所有注册好,以供后续选择使用。
//Registry.java
private final ModelLoaderRegistry modelLoaderRegistry;
private final EncoderRegistry encoderRegistry;
private final ResourceDecoderRegistry decoderRegistry;
private final ResourceEncoderRegistry resourceEncoderRegistry;
private final DataRewinderRegistry dataRewinderRegistry;
private final TranscoderRegistry transcoderRegistry;
private final ImageHeaderParserRegistry imageHeaderParserRegistry;
二、详解
Glide4.9.0 SourceGenerator 源码解析 提到ModelLoaders是实现model
->data
的转换。下面我们看看Glide是如何生成可用于特定model的ModelLoaders列表的。
以ModelLoaderRegistry
为例子,类图如下。可以看到Registry#append
方法会通过层层调用直到MultiModelLoaderFactory#append
,最后添加到MultiModelLoaderFactory#entries
列表中,实际是由Entry#factory#build
创建ModelLoader
,Entry#handles方法判断是否可以处理该类型数据。
那么是在什么时候调用Registry#append
注册内置的modelLoader
呢?答案是在GLide
的构造函数中,并没有完全展示所有,节选了一部分。
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) {
...
registry = new Registry();
...
registry
/* Models */
.register(new InputStreamRewinder.Factory(arrayPool))
.append(int.class, InputStream.class, resourceLoaderStreamFactory)
.append(
int.class,
ParcelFileDescriptor.class,
resourceLoaderFileDescriptorFactory)
...
}
Glide是如何从注册好的ModelLoader中找出我们需要使用的。
调用了 modelLoaderRegistry.getModelLoaders(model),直接看下一个方法。
//Registry.java
@NonNull
public <Model> List<ModelLoader<Model, ?>> getModelLoaders(@NonNull Model model) {
List<ModelLoader<Model, ?>> result = modelLoaderRegistry.getModelLoaders(model);
if (result.isEmpty()) {
throw new NoModelLoaderAvailableException(model);
}
return result;
}
主要是经过2重过滤。
//ModelLoaderRegistry.java
@NonNull
public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
//根据model.getClass第一重过滤
List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
int size = modelLoaders.size();
boolean isEmpty = true;
List<ModelLoader<A, ?>> filteredLoaders = Collections.emptyList();
//noinspection ForLoopReplaceableByForEach to improve perf
//根据handles方法第二重过滤
for (int i = 0; i < size; i++) {
ModelLoader<A, ?> loader = modelLoaders.get(i);
if (loader.handles(model)) {
if (isEmpty) {
filteredLoaders = new ArrayList<>(size - i);
isEmpty = false;
}
filteredLoaders.add(loader);
}
}
return filteredLoaders;
}
//可以看到第一重过滤是由multiModelLoaderFactory.build(modelClass)执行的。
@NonNull
private synchronized <A> List<ModelLoader<A, ?>> getModelLoadersForClass(
@NonNull Class<A> modelClass) {
List<ModelLoader<A, ?>> loaders = cache.get(modelClass);
if (loaders == null) {
loaders = Collections.unmodifiableList(multiModelLoaderFactory.build(modelClass));
cache.put(modelClass, loaders);
}
return loaders;
}
第一重过滤
//MultiModelLoaderFactory.java
@NonNull
synchronized <Model> List<ModelLoader<Model, ?>> build(@NonNull Class<Model> modelClass) {
try {
List<ModelLoader<Model, ?>> loaders = new ArrayList<>();
for (Entry<?, ?> entry : entries) {
if (alreadyUsedEntries.contains(entry)) {
continue;
}
//判断entry.modelclass是不是modelclass的父类。
if (entry.handles(modelClass)) {
alreadyUsedEntries.add(entry);
//调用entry.factory.build(this)
//entry.factory是ModelLoaderFactory接口。
//这里根据不同的ModelLoaderFactory实现类,会有不同的表现。
//主要功能就是创建一个modelloader。
//这里有一个注意点是MultiModelLoader的概念。
loaders.add(this.<Model, Object>build(entry));
alreadyUsedEntries.remove(entry);
}
}
return loaders;
} catch (Throwable t) {
alreadyUsedEntries.clear();
throw t;
}
}
第二重过滤
是由具体的ModelLoader接口实现类自己实现,不同的实现类不一样,例如:
//DataUriLoader.java
@Override
public boolean handles(@NonNull Model model) {
// We expect Model to be a Uri or a String, both of which implement toString() efficiently. We
// should reconsider this implementation before adding any new Model types.
return model.toString().startsWith(DATA_SCHEME_IMAGE);
}