, 其实分析glide的源码,不仅可以让人能更好的了解其内部工作原理以便能更好的使用该框架,更重要的是能从阅读代码种学习一些其他的东西,比如代码的组织设计策略,设计模式的灵活应用,甚至你可以剥离出一些有用的设计理念来应用到自己的开发中去,真是可以让你获益良多。

在《Glide之请求网络图片数据流程解析》这面博文中我就就接触了ModelLoader这个glide的组件,但是没有细说,本文就简单分析下。
具体的体现着这一句:

public boolean startNext() {//省略部分代码loadData = helper.getLoadData().get(loadDataListIndex++);//省略部分代码}

先进入DecodeHelper的getLoadData方法来看看ModelLoader的应用:

  //返回一个LoadData对象的集合List<LoadData<?>> getLoadData() {//省略部分代码//1、获取ModelLoader对象的集合List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);int size = modelLoaders.size();//2、遍历modelLoaders集合for (int i = 0; i < size; i++) {ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);//3、通过modelLoader对象获取LoadDataLoadData<?> current =modelLoader.buildLoadData(model, width, height, options);if (current != null) {loadData.add(current);}}return loadData;}

getLoadData方法主要做了两件事:
1、通过Registry对象的getModelLoaders(model)获取ModelLoaders对象的集合。注意如果这里的model对象就是通过load方法传入的对象,比如你load(“http://xxxx.img“),那么这个model就是String类型的对象。此篇博文中我们就假设model为String的类型来分析。(getModelLoaders方法后面会具体分析)
2、遍历集合,使得每一个ModelLoader通过buildLoadData创建一个LoadData对象。

那么这里可以引申出两个问题:
1、ModelLoader是什么?
2、Registry对象是什么时候初始化的?
3、Registry对象里持有的ModelLoader集合所包含的各个ModelLoadder 是什么时候添加的?
下面就带着上面的问题来继续下面的博文。ModelLoader是一个接口,该接口里有一个名为LoadData的内部类,且该接口提供了一个buildLoadData方法来创建一个LoadData对象,该方法可以看作是一个工厂方法:

public interface ModelLoader<Model, Data> {//加载数据用的LoadDataclass LoadData<Data> {public final Key sourceKey;public final List<Key> alternateKeys;//真正加载数据的地方public final DataFetcher<Data> fetcher;public LoadData(Key sourceKey, DataFetcher<Data> fetcher) {this(sourceKey, Collections.<Key>emptyList(), fetcher);}public LoadData(Key sourceKey, List<Key> alternateKeys, DataFetcher<Data> fetcher) {}}//创建LoadData的工厂方法LoadData<Data> buildLoadData(Model model, int width, int height, Options options);boolean handles(Model model);
}

纵观LoadData的代码,里面除了两个构造器用来初始化LoadData的属性之外,并没有提供任何的方法来加载数据,且里面DataFetcher的类引用,我们有理由相信真正加载数据的类就是DataFetcher!!!当然在《Glide之请求网络图片数据流程解析》已经略作说明。

在glide中ModelLoader有如下实现:

另外glide中还提供了ModelLoaderFactory的工厂接口来创建ModelLoader:

public interface ModelLoaderFactory<T, Y> {ModelLoader<T, Y> build(MultiModelLoaderFactory multiFactory);void teardown();
}

该接口工厂glide中也提供了一些实现:

需要注意的这这些工厂类的具体实现是都是ModelLoader接口具体实现的内部类。
ModelLoader 先简单分析到这儿,从代码设计上来看其主要作用就是创建一个LoadData对象来处理具体到业务逻辑。上文中我们是通过Registry对象来获取ModelLoader的集合的,Registry的初始化是在Glide的构造器里面初始化的,且初始化Registry的同时也把glide内部提供的ModelLoaderFactory的具体实现(见上图)注册到Registry类中:

 Glide(//省略一大堆参数) {//省略部分代码registry = new Registry();/*省略部分代码*//*注册ModelLoader和ModelLoaderFactory相关的对象*/registry.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>()).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())/*省略部分代码*/}

上面除了registry方法之外,大部分都是通过prepend和append方法来注册ModelLoader或者ModelLoaderFactory对象的,进入其append方法来看看:

 private final ModelLoaderRegistry modelLoaderRegistry;public Registry() {this.modelLoaderRegistry = new ModelLoaderRegistry(exceptionListPool);//省略部分代码}public <Model, Data> Registry append(Class<Model> modelClass, Class<Data> dataClass,ModelLoaderFactory<Model, Data> factory) {modelLoaderRegistry.append(modelClass, dataClass, factory);return this;}

最终将添加的ModelLoaderFactory都通过modelLoaderRegistry对象的append来保存起来。所以进入ModelLoaderRegistry类的append方法去看:

  //一个MultiModelLoaderFactory对象的引用private final MultiModelLoaderFactory multiModelLoaderFactory;//构造器ModelLoaderRegistry(MultiModelLoaderFactory multiModelLoaderFactory) {this.multiModelLoaderFactory = multiModelLoaderFactory;}public synchronized <Model, Data> void append(Class<Model> modelClass, Class<Data> dataClass,ModelLoaderFactory<Model, Data> factory) {//MultiModelLoaderFactory的append  multiModelLoaderFactory.append(modelClass, dataClass, factory);cache.clear();}

几经辗转,最总通过Registry注册进来的ModerLoaderFactory是转移到了MultiModelLoaderFactory这个类中,看看该类的方法都是做了什么:

synchronized <Model, Data> void append(Class<Model> modelClass, Class<Data> dataClass,ModelLoaderFactory<Model, Data> factory) {//调用add方法  add(modelClass, dataClass, factory, true);}
//entry集合类
private final List<Entry<?, ?>> entries = new ArrayList<>();private <Model, Data> void add(Class<Model> modelClass, Class<Data> dataClass,ModelLoaderFactory<Model, Data> factory, boolean append) {//用add方法的参数构建一个entry对象  Entry<Model, Data> entry = new Entry<>(modelClass, dataClass, factory);entries.add(append ? entries.size() : 0, entry);}

上面的方法也不复杂,无非就是将Registry添加进来的factory最终构成Enry对象添加到entries集合里面,说白了就是几个对象的辗转腾挪,然后构建一个Entry来统一管理,放入到集合里面而已。

private static class Entry<Model, Data> {private final Class<Model> modelClass;@Synthetic final Class<Data> dataClass;@Synthetic final ModelLoaderFactory<Model, Data> factory;
}

写到此处,先捋一捋上面的讲述:
1、ModelLoader主要负责创建一个LoadData对象
2、ModelLoaderFactory顾名思义就是构建ModelLoader对象
3、通过Registry这个对象将各个ModelLoaderFactory 注册进来,说白来就是注册到MultiModelLoaderFactory中,只不过这些ModelLoaderFactory最终又单独的剥离出一个Entry对象放入集合中,从某角度来看Registry倒是可以看作一个门面模式来看待。

综合以上三点想要获取LoadData对象,也只是简单的几步而已:
1、遍历MultiModelLoaderFactory的entries集合,根据model类型获取对应类型的ModelLoaderfactory对象
2、调用ModelLoaderFactory的build方法得到一个ModelLoader对象
3、调用ModelLoader的buildLoadData方法获取具体的LoadData对象。
上面说明有些啰嗦了,可以用下图表示其关系:

到此为止这几个类的关系算是介绍完毕,那么让我们继续文章开头所说的Registry类中的getModelLoaders(Model)方法,其中model我们仍然认为是String类型的数据,根据上图的关系我们直接看MultiModelLoaderRegistry类中的getModelLoaders方法:

 public synchronized <A> List<ModelLoader<A, ?>> getModelLoaders(A model) {//1、根据model获取ModelLoader集合List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));//2、遍历集合中的ModelLoader对象,判断ModelLoader是否处理了当前的modelint size = modelLoaders.size();List<ModelLoader<A, ?>> filteredLoaders = new ArrayList<>(size);for (int i = 0; i < size; i++) {ModelLoader<A, ?> loader = modelLoaders.get(i);//如果该ModelLoader的handles返回了trueif (loader.handles(model)) {filteredLoaders.add(loader);}}return filteredLoaders;}

上面的核心代码就是调用getModelLoadersForClass方法来获取ModelLoader集合,但是呢,glide中有这么多的ModelLoader到底哪些是当前所需要的呢,这就要根据ModelLoader的handles来匹配了,这个不必细说,我们来看看getModelLoadersForClass都做了哪些:

 //此时modelClass是String.classprivate <A> List<ModelLoader<A, ?>> getModelLoadersForClass(Class<A> modelClass) {//根据modelClass来获取缓存中的ModelLoader集合List<ModelLoader<A, ?>> loaders = cache.get(modelClass);//集合不存在则调用multiModelLoaderFactory的build方法if (loaders == null) {loaders = Collections.unmodifiableList(multiModelLoaderFactory.build(modelClass));cache.put(modelClass, loaders);}return loaders;}

getModelLoadersForClass方法逻辑很简单,就是先从缓存中通过modelClass获取对应的ModelLoader集合,缓存没有则调用multiModelLoaderFactory的build方法,该方法如下:

 synchronized <Model> List<ModelLoader<Model, ?>> build(Class<Model> modelClass) {List<ModelLoader<Model, ?>> loaders = new ArrayList<>();//遍历entries集合for (Entry<?, ?> entry : entries) {//省略部分代码if (entry.handles(modelClass)) {//省略部分代码//根据entry对象创建具体的ModelLoaderloaders.add(this.<Model, Object>build(entry));//省略部分代码}}return loaders;}

上面代码的主要逻辑就是遍历通过Registry注册而声称的entries集合,然后根据modelClass来匹配具体entry,然后调用build(entry)方法来获取具体的ModelLoader对象,根据上面的讲解以及上面的图示,我们不难猜出build(entry)方法其实就是调用了其内部的ModelLoaderFactory对象build而已,有代码为证:

  private <Model, Data> ModelLoader<Model, Data> build(Entry<?, ?> entry) {return (ModelLoader<Model, Data>)
//调用factory的build方法。   Preconditions.checkNotNull(entry.factory.build(this));}

到此为止ModelLoader对象的真正创建过程已经解析完毕,其实对象的创建过程无非就是那么几种,但是我们的glide确百转千回,为了得到LoadData对象先是提供了ModelLoader接口,又提供了ModelLoaderFactory;总的来说由ModelLoaderFactory接口创建ModelLoader对象,再由ModelLoader来创建LoadData可以说做了大量的“额外”工作,但是呢不得不说这个“额外”工作从代码设计的觉度来说着实可以用来借鉴一二,具体怎么借鉴,仁者见仁智者见智了,有时候某些东西还真是只可意会不可言谈。

在《Glide之请求网络图片数据流程解析》中我们知道最终是通过HttpUrlFetcher来完成最终的数据加载的(当然缓存不算),我们本篇就来详细说说这个HttpUrlFetcher是怎么蹦跶出来的。

从上文我们知道了获取ModelLoader的方法,且因为我们load方法传入的是一个String类型url,也就是说我们的model就是String.class,在Registry中注册ModelLoderFactory的时候,以String.class为model的ModelLoaderFactory有如下几个:

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

还是进入getLoadData的debug模式,我们获取的modelLoader 的集合其实是一个StringLoader:

因为我们的model传入的是http的URL,所以看上面的StringLoader即可。先来看看ModelLoaderFactory初始化StringLoader的build方法:

  @Overridepublic ModelLoader<String, InputStream> build(MultiModelLoaderFactory multiFactory) {return new StringLoader<>(multiFactory.build(Uri.class, InputStream.class));}

可以看出StringLoader的初始化是需要另外一个ModdelLoader 作为参数的,从StringLoader的构造器代码中可以出这一点:

  private final ModelLoader<Uri, Data> uriLoader;public StringLoader(ModelLoader<Uri, Data> uriLoader) {this.uriLoader = uriLoader;}

uriLoader的初始化是通过如下代码来初始化

//注意此处是两个参数的build方法,上文讲的是一个参数的build方法
multiFactory.build(Uri.class, InputStream.class)

此时通过multiFactory构建ModelLoader的model类型是Uri.class,当然以Uri.class为Model的Mode Loader也很多,在此不一一列出,看看此build重载方法都做了什么:

//modelClass == Uri.class
//dataClass == InputStream.classpublic synchronized <Model, Data> ModelLoader<Model, Data> build(Class<Model> modelClass,Class<Data> dataClass) {try {List<ModelLoader<Model, Data>> loaders = new ArrayList<>();for (Entry<?, ?> entry : entries) {//注意此处if (entry.handles(modelClass, dataClass)) {alreadyUsedEntries.add(entry);loaders.add(this.<Model, Data>build(entry));alreadyUsedEntries.remove(entry);}}//当model匹配不止一个ModelLoader的时候if (loaders.size() > 1) {//此factory为MultiModelLoaderFactory的嵌套类return factory.build(loaders, exceptionListPool);} else if (loaders.size() == 1) {return loaders.get(0);} else {//省略部分代码}} catch (Throwable t) {//省略部分代码}}

阅读上面代码发现,当model.class匹配了多个ModelLoader的时候调用了factory的build方法返回一个MultiModelLoader,该build 的方法的第一个参数就是我们匹配的多个ModelLoader对象的集合:

  static class Factory {public <Model, Data> MultiModelLoader<Model, Data> build(List<ModelLoader<Model, Data>> modelLoaders, Pool<List<Exception>> exceptionListPool) {//返回MultiModelLoader对象return new MultiModelLoader<>(modelLoaders, exceptionListPool);}}

所以我们构建StringLoader的时候需要的uriLoader的时候我们传了两个参数进行ModelLoader的匹配:Uri.class和InputStream.class,其中Uri.class 作为model.class而InputStream.class作为data.class来调用entryhandles(modelClass, dataClass)来进行匹配,在Registry注册ModelLoaderFactory的时候负责上述两种的MolderLaoderFactory如下:

.append(Uri.class, InputStream.class, new HttpUriLoader.Factory()).append(Uri.class, InputStream.class, new AssetUriLoader.StreamFactory(context.getAssets())).append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory())//以下仍然省略几种

所以此时StringLoader的uriLoader就是一个MultiModelLoader对象,也就是说MultiModelLoader里面有若干个匹配model.class和dataclass的集合,且从面的debug图来看,集合中的一个ModerLoader就是HttpUriLoder.

按照上文缩手,ModelLaoder的初始化是由Factory来完成的,所以我们只关心HttpUriLoader的Factory,看看该Factory的build方法:

@Overridepublic ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {return new HttpUriLoader(multiFactory.build(GlideUrl.class, InputStream.class));}

同样的,在构造HttpUriLoader的时候需要根StringLoader一样同样需要一个ModelLoader对象,该对象的变量名是urlLoader,且传入的model为GlideUrl.class,data.class为InputStream.class,符合提条件的ModeLoder就是HttpGlideUrlLoader。

 .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())

通过前面几片博文的讲解,我们知道ModelLoader提供buildLoadData方法来返回一个LoadData方法来加载数据,所以看看HttpUriLoader的buildData返回的LoadData是什么鬼:

  public LoadData<InputStream> buildLoadData(Uri model, int width, int height, Options options) {//调用HttpGlideUrlLoader的buildLoadData方法return urlLoader.buildLoadData(new GlideUrl(model.toString()), width, height, options);}

可以发现HttpUriLoader的buildLoadData方法直接调用了HttpGlideUrlLoader的buildLoadData方法,该方法如下:

 public LoadData<InputStream> buildLoadData(GlideUrl model, int width, int height,//省略部分代码return new LoadData<>(url, new HttpUrlFetcher(url, timeout));}

看到了把,绕了十万八千里HttpUrlFetcher对象犹抱琵琶“不”遮面了,根据《Glide之请求网络图片数据流程解析》这片博文,HttpUrlFetcher就是访问服务器获取图片说句的类了。

所以LoadData只是一个外壳,真正加载数据的还是LoadData持有的DataFetcher接口,该接口在glide的实现类由如下几个:

当然到了此处,本篇博文就结束类,回头再看看着实有些啰嗦,不当之处,欢迎批评指正

Glide 4.x之ModelLoader简单分析相关推荐

  1. R语言splines包构建基于logistic回归的自然样条分析:南非心脏病数据集、非线性:基函数展开和样条分析、你简单分析的不重要特征,可能只是线性不显著、而非线性是显著的

    R语言splines包构建基于logistic回归的自然样条分析:南非心脏病数据集.非线性:基函数展开和样条分析.你简单分析的不重要特征,可能只是线性不显著.而非线性是显著的 目录

  2. [EntLib]微软企业库5.0 学习之路——第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—上篇...

    在完成了后,今天开始介绍企业库中的新模块:Cryptographer(加密模块),这个模块在日常的大多数项目的作用非常重要,例如:网站会员密码.身份证号.网站配置等,通过对信息进行加密可以保证项目数据 ...

  3. FFmpeg资料来源简单分析:libswscale的sws_getContext()

    ===================================================== FFmpeg库函数的源代码的分析文章: [骨架] FFmpeg源码结构图 - 解码 FFmp ...

  4. howdoi 简单分析

    对howdoi的一个简单分析. 曾经看到过下面的这样一段js代码: try{doSth(); } catch (e){ask_url = "https://stackoverflow.com ...

  5. Mac与Phy组成原理的简单分析

    Mac与Phy组成原理的简单分析 2011-12-28 15:30:43 //http://blog.chinaunix.net/uid-20528014-id-3050217.html 本文乃fir ...

  6. python做数据可视化的代码_Python数据可视化正态分布简单分析及实现代码

    Python说来简单也简单,但是也不简单,尤其是再跟高数结合起来的时候... 正态分布(Normaldistribution),也称"常态分布",又名高斯分布(Gaussiandi ...

  7. ASIHTTPRequest源码简单分析

    2019独角兽企业重金招聘Python工程师标准>>> 1.前言 ASIHttprequest 是基于CFNetwork的,由于CFNetwork是比较底层的http库,功能比较少, ...

  8. Hessian 源码简单分析

    Hessian 源码简单分析 Hessian 是一个rpc框架, 我们需要先写一个服务端, 然后在客户端远程的调用它即可. 服务端: 服务端通常和spring 做集成. 首先写一个接口: public ...

  9. python预测股票价格tushare_用tushare对股票进行简单分析

    用tushare对股票进行简单分析(仅供交流学习) import numpy as np import pandas as pd import matplotlib.pyplot as plt imp ...

  10. 智能情绪分析技术_简单分析人工智能的表现在计算机网络应用技术中的优势

    简单分析人工智能的表现在计算机网络应用技术中的优势 大数据时代背景下, 计算机网络技术迅猛发展, 而人工智能技术的发展也进一步推动了计算机网络技术的发展, 两者相互融合, 相互促进, 实现了双赢发展. ...

最新文章

  1. 别再抱怨了,国内这么多优秀的Android资源你都知道吗?
  2. angular学习笔记(三十)-指令(4)-transclude
  3. 在SAP Cloud Platform ABAP编程环境里打印系统变量
  4. IOS基础之iPad的屏幕旋转方向判断
  5. java ref object_深入探讨 java.lang.ref 包
  6. 【笔试/面试】—— Linux 查看 cpu 和内存使用情况
  7. caffe数据格式(Google Protocol Buffers)
  8. vue-router的编程式导航
  9. python制作简单计算器
  10. 基于MTK方案AG3335芯片设计的款超小型超低功耗定位器
  11. 找回 Windows 丢失的拨号密码
  12. C语言自学之路五(选择语句详解)
  13. 施努卡:锂电池模组生产线(锂电池模组是什么)
  14. html5怎么让表格居中,HTML怎么让表格居中
  15. 使用链表实现栈stack
  16. 大数据技术基础实验十三:Kafka实验——订阅推送示例
  17. Python开发网站
  18. 【Orz】喜闻乐见的原创题被虐...
  19. 双面女间谍第一至五季/全集Alias迅雷下载
  20. 以前写的网页游戏辅助工具源码 传奇类的HOOK 封包 按钮

热门文章

  1. java和基岩怎么联机_JAVA和基岩版要同步了
  2. vue-awesome-swiper:依赖于6.X版本Swiper时轮播分页器下方小圆点不显示
  3. 计算机组成原理:计算机内负数二进制求得方式
  4. Java8 LocalDateTime和Date相互转换
  5. Java直接遍历并读取zip压缩文件的内容以及错误处理
  6. 零拷贝的基本原理及使用Java通过零拷贝实现数据传输
  7. ML/DL-复习笔记【四】- DeepLab系列模型总结
  8. CVPR2022 | 移动端手部三维重建
  9. 清退117名博士、119名硕士!研究生“严出”成人才培养大趋势
  10. 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。