Glide数据输入输出
基础概念
在正式开始之前先明确一些概念
Glide输入: 我们日常在使用Glide的时候,通过load可以加载不同的资源类型例如文件,字符串等待。
我们把load的不同类型称为不同的输入。
Glide输出: Glide RequestManager提供了许多的as重载方法,
通过不同的as我们可以指定不同的输出类型。
ModelLoader: 是一个泛型接口,最直观的翻译是模型加载器。ModelLoader标记了它能够加载什么类型的数据,以及加载后返回什么样的数据类型。注意这里说说的返回的数据类型并不是我们想要的输出。ModelLoader定义如下
public interface ModelLoader<Model, Data> {
class LoadData<Data> {
//数据加载的key
public final Key sourceKey;
public final List<Key> alternateKeys;
//获取数据的接口,对应获取不同类型的数据实现
public final DataFetcher<Data> fetcher;
public LoadData(@NonNull Key sourceKey, @NonNull DataFetcher<Data> fetcher) {
this(sourceKey, Collections.<Key>emptyList(), fetcher);
}
public LoadData(@NonNull Key sourceKey, @NonNull List<Key> alternateKeys,
@NonNull DataFetcher<Data> fetcher) {
this.sourceKey = Preconditions.checkNotNull(sourceKey);
this.alternateKeys = Preconditions.checkNotNull(alternateKeys);
this.fetcher = Preconditions.checkNotNull(fetcher);
}
}
//创建LoadData 对象
@Nullable
LoadData<Data> buildLoadData(@NonNull Model model, int width, int height,
@NonNull Options options);
//判断当前的ModelLoader是否能够处理这个model
boolean handles(@NonNull Model model);
}
DataFetcher: 用于进行数据加载,不同的类型有不同的DataFetcher
SourceGenerator远程数据加载过程
@Override
public boolean startNext() {
//...
boolean started = false;
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
代码流程:
通过DecodeHelper获取LoadData,遍历每一个LoadData;
查看当前LoadData加载出来的数据能不能,转换成我们想要的输出数据,如果可以的话就是用当前loadData进行数据加载。
DecodeHelpe#getLoadData()
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
//此处的model就是我们 通过调用load传递进来的参数 即输入
List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = modelLoaders.size(); i < size; i++) {
ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
//通过modelLoader 构建loadData
LoadData<?> current =
modelLoader.buildLoadData(model, width, height, options);
if (current != null) {
loadData.add(current);
}
}
}
return loadData;
}
ModelLoaderRegistry#getModelLoaders
getModelLoaders()实现的位置在ModelLoaderRegistry#getModelLoaders
public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
//获取对应的modelLoader
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
for (int i = 0; i < size; i++) {
ModelLoader<A, ?> loader = modelLoaders.get(i);
//判断对应的modelLoader是否有能力处理对应的model
if (loader.handles(model)) {
if (isEmpty) {
filteredLoaders = new ArrayList<>(size - i);
isEmpty = false;
}
filteredLoaders.add(loader);
}
}
return filteredLoaders;
}
getModelLoadersForClass主要是通过MultiModelLoaderFactory#build。然后MultiModelLoaderFactory会遍历所有已经注册的ModelLoader,只要当前的model是已经注册model的子类或者对应的实现,那么就会把对应的ModelLoader添加到待返回的集合中。
DecodeHelper#hasLoadPath
boolean hasLoadPath(Class<?> dataClass) {
return getLoadPath(dataClass) != null;
}
<Data> LoadPath<Data, ?, Transcode> getLoadPath(Class<Data> dataClass) {
return glideContext.getRegistry().getLoadPath(dataClass, resourceClass, transcodeClass);
}
可以看到hasLoadPath代码其实非常简单,就是获取一个LoadPath集合。获取的时候传递了三个参数 DataFetcher加载出来的数据类型dataClass,resourceClass ,transcodeClass
getLoadPath参数
对于resourceClass ,transcodeClass在DecodeHelper定义如下:
private Class<?> resourceClass;
private Class<Transcode> transcodeClass;
他们在init方法中进行初始化,经过层层代码的流转我们发现最终的参数初始化来自于RequestBuilder#obtainRequest
private Request obtainRequest(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
model,
//该参数会在调用as系列方法后初始化,指向的是我们想要的输出类型。
transcodeClass,
//指向的是RequestBuilder 自身
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
而RequestOptions#getResourceClass返回的resourceClass默认情况下返回的是Object,而在asBitmap和asGifDrawable会做其它的转换。
private static final RequestOptions DECODE_TYPE_BITMAP = decodeTypeOf(Bitmap.class).lock();
private static final RequestOptions DECODE_TYPE_GIF = decodeTypeOf(GifDrawable.class).lock();
@NonNull
@CheckResult
public RequestBuilder<Bitmap> asBitmap() {
return as(Bitmap.class).apply(DECODE_TYPE_BITMAP);
}
public RequestBuilder<GifDrawable> asGif() {
return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
}
getLoadPath执行过程
getLoadPath最终会调用Registry#getLoadPath
@Nullable
public <Data, TResource, Transcode> LoadPath<Data, TResource, Transcode> getLoadPath(
@NonNull Class<Data> dataClass, @NonNull Class<TResource> resourceClass,
@NonNull Class<Transcode> transcodeClass) {
//先获取DecodePath
List<DecodePath<Data, TResource, Transcode>> decodePaths =
getDecodePaths(dataClass, resourceClass, transcodeClass);
if (decodePaths.isEmpty()) {
result = null;
} else {
result =
new LoadPath<>(
dataClass, resourceClass, transcodeClass, decodePaths, throwableListPool);
}
loadPathCache.put(dataClass, resourceClass, transcodeClass, result);
return result;
}
private <Data, TResource, Transcode> List<DecodePath<Data, TResource, Transcode>> getDecodePaths(
@NonNull Class<Data> dataClass, @NonNull Class<TResource> resourceClass,
@NonNull Class<Transcode> transcodeClass) {
List<DecodePath<Data, TResource, Transcode>> decodePaths = new ArrayList<>();
//遍历所有资源解码器,获取能够解析当前输入dataClass的解码器
List<Class<TResource>> registeredResourceClasses =
decoderRegistry.getResourceClasses(dataClass, resourceClass);
for (Class<TResource> registeredResourceClass : registeredResourceClasses) {
//获取能够解析当前输入dataClass且将数据转变成我们想要的transcodeClass类型的转换类
List<Class<Transcode>> registeredTranscodeClasses =
transcoderRegistry.getTranscodeClasses(registeredResourceClass, transcodeClass);
for (Class<Transcode> registeredTranscodeClass : registeredTranscodeClasses) {
//获取对应的所有解码器
List<ResourceDecoder<Data, TResource>> decoders =
decoderRegistry.getDecoders(dataClass, registeredResourceClass);
//转换类
ResourceTranscoder<TResource, Transcode> transcoder =
transcoderRegistry.get(registeredResourceClass, registeredTranscodeClass);
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
DecodePath<Data, TResource, Transcode> path =
new DecodePath<>(dataClass, registeredResourceClass, registeredTranscodeClass,
decoders, transcoder, throwableListPool);
decodePaths.add(path);
}
}
return decodePaths;
}
整个过程涉及到两个关键类LoadPath DecodePath。
LoadPath 由数据类型datacalss 和 DecodePath组成
DecodePath 由数据类型dataclass 解码器 ResourceDecoder 集合 和资源转换 ResourceTranscoder 构成。总体上而言 一个LoadPath的存在代表着可能存在一条路径能够将ModelLoader加载出来的data解码转换成我们指定的数据类型。
DocodeJob数据解码的过程
在 Glide DecodeJob 的工作过程我们知道SourceGenerator在数据加载完成之后如果允许缓存原始数据会再次执行SourceGenerator#startNext将加载的数据进行缓存,然后通过DataCacheGenerator从缓存文件中获取。最终获取数据成功后会调用DocodeJob#onDataFetcherReady
作者:小小小小小鹿
链接:https://juejin.cn/post/7036389645168410655
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。