–>

概况

Glide 是一个资源从不同形态之间相互转换的框架,而不仅仅是一个图片加载框架。 下图是 Glide 的总体架构。

Glide 总体架构 主要包括一下几个步骤。

  1. 资源->model : 把资源(URL, uri , File ,资源 ID , Drawable ,byte[]等)转换成一个 Model 。
  2. Model->Data : 通过 DecodeJob 把 Model 转换成 Data ,例如 URL 进行网络请求得到InputStream
  3. Data->Resouce : 通过 DecodeJob 把 Data 转换成 Resource ,主要是通过解码成所需要的格式,比如把 InputStream 转换成Bitmap
  4. Resouce->Resouce : 通过 Transformation 对解码后的 Resource 进行变化操作,比如常见的 CenterCrop
  5. 显示到UI : 通过 Transition 把 Resource 到显示到 Target 上

Glide 加载流程

model(数据源)
-->data(转换数据)
-->decode(解码)
-->transformed(缩放)
-->transcoded(转码)
-->encoded(编码保存到本地)

关键类介绍

Model

数据的最初来源,可能是 URL ,或者资源 ID ,文件,甚至 Feed 流中的一条 Feed ,也就是我们使用Glide.with(this).load(xxx)里面的 xxx 。

Data

Data 是能够被编码器识别的数据,包括byte[]数组, InputStream 流和 File 文件等。 Model 并不能直接解析为图片,是需要转换才能作为数据解析的数据源,比如一个 url 是要转换成网络流 InputStream 才能被解析为图片的。这个转换后的东西叫 Data 。

ModelLoader

如此多类型的 Model(比如 URL , uri , File ,资源 ID ,视频等)和如此多的 Data 。不同的 Model 有不同的加载方法。 Glide 使用到了 ModelLoader ,每一种 Model 都对应一个 ModelLoader 。如下图,定义了如此多的 ModelLoader 。当然,也可以自定义 ModeLoader ,例如通过 id 得到一个图片,这个后面也会讲到 源码入下。

public interface ModelLoader<Model, Data> {
  class LoadData<Data> {
    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);
    }
  }
  /** 给定 model 宽高信息 已经 Options 生成LoadData<?> **/
  @Nullable
  LoadData<Data> buildLoadData(@NonNull Model model, int width , int height ,@NonNull Options options);

  boolean handles(@NonNull Model model);
}
  • 通过 buildLoadData() 生产一个 LoadData 的对象, LoadData 里面有个成员变量DataFetcher<>,
  • 通过 hanler() 方法判断这个 ModelLoader 能否处理这种 Model.

ModelLoaderFactory

ModelLoader 的生产者,用来 build() ModelLoder 的

public interface ModelLoaderFactory<T, Y> {
  @NonNull
  ModelLoader<T, Y> build(@NonNull MultiModelLoaderFactory multiFactory);

  void teardown();
}

我们往 Regitry 注册 Loader 的时候,可以清晰的看到其实往里添加的主要是三个内容 Class Class 以及 ModelLoaderFactory 。没错 ModelLoaderFactory 就是构建 ModelLoder 的工厂类,前两个参数指明了被处理的数据类型和加载成的数据类型。例如下面这种。

.append(File.class, ByteBuffer.class, new ByteBufferFileLoader.Factory())

被处理的数据类型是文件,加载的数据类型是字节数组。

MultiModelLoaderFactory

往 Registry 对象中注册的 ModelLoaderFactory 最终都是保存在MultiModelLoaderFactory

DataFetcher

public interface DataFetcher<T> {

  interface DataCallback<T> {
    void onDataReady(@Nullable T data);
    void onLoadFailed(@NonNull Exception e);
  }
  //加载资源文件,这些资源文件可能是字节数组,文件等,都是用现在抽象 T 代表
  void loadData(@NonNull Priority priority, @NonNull DataCallback<? super T> callback);

  void cleanup();

  void cancel();

  @NonNull
  Class<T> getDataClass();

  @NonNull
  DataSource getDataSource();
}
  1. 泛型类, T 表示要加载的 Data 的类型。 也是获取 Data 的抽象类,
  2. 规定了获取数据通过调用 loadData() ,
  3. 一个 DataCallBack 实例,当 Data 获取成功会调用 callBack 的 onDataReady() ,当获取失败的使时候会调用onLoadFailed(Exception e)

也有各种实现类,用来加载不同的资源文件。例如 HttpUrlFetcher 中的 loadData() ,就是通过 HttpURLConnection ,把 URL 转换成InputStream

DataFetcherGenerator

DataFetcher 的生产者

interface DataFetcherGenerator {

  interface FetcherReadyCallback {
    //重新执行startNext()
    void reschedule();
    // data 能直接编码的 Data 数据,
    // onDataFetcherReady执行的时候,不但已经创建了 DataFetcher 对象,并且 DataFetcher 已经获取到了 Data 对象
    void onDataFetcherReady(Key sourceKey, @Nullable Object data,
        DataFetcher<?> fetcher, DataSource dataSource ,Key attemptedKey);

    void onDataFetcherFailed(Key attemptedKey, Exception e ,
        DataFetcher<?> fetcher,DataSource dataSource);
  }
  //获取一个 DataFetcher 并且开始执行获取 Data 的操作,如果开始执行了,则返回 true ,否则返回false
  boolean startNext();
  //取消获取
  void cancel();
}

它的实现类有三个

  • ResourceCacheGenerator 从磁盘获取缓存过的数据,是转换过的数据,可以直接供 View 使用。例如包含缩减采样/转换资源数据的缓存文件生成 DataFetchers 将 URL 加载的原图压缩后又缓存起来, glide 能够缓存不同尺寸图片的原因就是在这里,
  • DataCacheGenerator 从磁盘中获取原始的缓存数据,这是原始数据,不能供 View 直接使用,例如从包含原始未修改源数据的缓存文件生成 DataFetchers 从原始的 Request 加载到二进制流直接缓存,比如 URL 加载到原图的缓存
  • SourceGenerator 从数据源中获取数据,会涉及到缓冲测量 ,跳过缓存直接从原始的 Request 获取请求

DecodeJob

负责从缓存数据或者原始资源解码资源并应用转换和转码的类,它实现了 Runnable 接口,是真正的加载线程的入口。

ResourceDecoder

Data 转 Resource 的类 , decode() 进行解码

ResourceTranscoder

Resource 互转工作的类 trasncode() 进行转码

Resource

一个包装类,它 wrap 一个对象,使这个对象可以通过对象池进行缓存与重用

Model 转换成Data

Model 转成 Data 的流程就是:通过DecodeJob:runGenerators()生成一个 DataFetcherGenerator ,然后执行 startNext() 方法,通过 buildLoadData() 创建一个 ModelLoader ,最后通过 loadData ,把该 model 转换成Data.

DecodeJob:runGenerators()
  -->DataFetcherGenerator:startNext()
  -->ModelLoader:buildLoadData()
  -->DataFetcher:loadData()

Data转换Resource

有了 ModeLoader 和 DataFetcher 的设计, Glide 就能把原始的请求从不同的地方加载到内存中了,这个时候这份数据还只是单纯的携带了数据格式的二进制。也就是 Data ,我们需要解码,剔除原始格式信息,然后重新编码,将其转换成不同的格式,比如把 JPG 先解码然后转码成 Bitmap ,或者转码成 GIF ,解码以及转码后的数据我们也称为 Resource 。 由于框架的设计决定需要转码的格式不定,解码的格式也不定。采用了模板设计模式处理,调用 ResourceDecoder 的 decode() 进行解码,使用 ResourceTranscoder 中的 trasncode() 进行转码。 从 Registry 中获取所有的 ResourceDecoder 和 ResourceTranscoder ,然后判断哪个解码器或转码器适合当前格式,直接调用相关的 decode 和 transcode 方法就可以了。

编码

Data 转 Resource ,将 url String file 等通过网络加载文件读取等方式转换最终加载成文件, Bitmap , Drawable , Gif 等的过程。

转码

Resource 转 Resouce 获取到的资源直接能够灵活的转换,包括 bitmap 转成字节数组,字节数组转成 bitmap 转 Drawable , gif 转字节数组等

还以刚才 HttpUrlFetcher 为例 把 URL 转 InputStream , 经过重重调用,最终会执行到 DecodePath 的 decode 中

// DecodePath.java
public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width , int height ,
     @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
       //解码 Data
   Resource<ResourceType> decoded = decodeResource(rewinder, width , height , options);
   Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
   //重新编码,转换成不同的格式
   return transcoder.transcode(transformed, options);
 }
  1. decodeResource()中就会执行到 decoder.decode()。
    private Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder, int width ,
     int height , @NonNull Options options, List<Throwable> exceptions) throws GlideException {
     Resource<ResourceType> result = null;
     for (int i = 0, size = decoders.size(); i < size; i++) {
       ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
       ...
       result = decoder.decode(data, width , height , options);
       ...
     }
     ...
     return result;
      }
    

    而这个 decoder ,就是 ResourceDecoder ,有多种类型 如下图, ResourceDecoder 的种类

  2. transcoder.transcode() 就会进行转码 transcoder 就是 ResourceTranscoder ,有很多子类

Resouce 转换Resouce

通过 Transformation 对解码后的 Resource 进行变化操作,比如常见的 CenterCrop ,变化后还是Resource

主要是在 Resource transformed = callback.onResourceDecoded(decoded);

缓存原理

源码分析 - Glide4 之 缓存原理

源码分析

源码分析 - Glide4 之 with() 和 load()

源码分析 - Glide4 之 into()

知识点

  1. Glide通过手动添加一个隐藏的 SupportRequestMangerFragment 对象,通过监听他的生命周期的变化,进而达到监听宿主 Activity 生命周期的目的,从而可以做 pauseRequest() 等操作
  2. 在 RequestManagerFragment 的构造函数中,注入的一个生命监听器 ActivityFragmentLifecycle ,并且在 Fragment 各个生命周期中,调用对应的方法,而 ActivityFragmentLifecycle 也紧接着会调用 LifecycleListener 监听器,而这个监听器其实就是 RequesManager ,是从 RequestManagerFragment 中取得 RequestManager ,如果没有,则创建一个,同时把这个 RequestManager 添加到 ActivityFragmentLifecycle 中 RequestManager 。对于同一个上下文来说,是唯一的
  3. 真正和 Activity 绑定在一起的就是这个 RequestManager 对象,所有生命周期的变动也是通过 RequestManger 进行分发的,
  4. LifecycleListener 和 LifeCircle 的作用,无非就是找到注册地方,和结束对象,
  5. RequestOptions 主要涉及图片的展示,
  6. RequestManagerRetriever RequestManager的检索器 Retriever 猎犬的意思
  7. Glide.with()最后返回一个请求管理工具,那就是 RequestManger
  8. RequestBuilder ,通过 as() 创建,即一个请求的构建者
  9. Glide就通过RequestManager、RequestOption、Request,构建了一个请求序列,并通过监听生命周期来动态管理 Request 的开启、暂停、恢复、销毁等。
  10. Glide将每一个请求都封装成一个解码任务 DecodeJob ,并扔到线程池中,一次来开启任务的异步加载
  11. 加载网络图片的有 HttpUriLoader 和UriLoader
  12. LoadPath 主要适用于解码和转换数据
  13. TargetTracker 和 RequestTarcker 分别对 target 和 Request 做了一个管理
    • TargetTracker 类简单,有点类似一个扩展的 List 结构,也就是保持了当前 RequestManger 在处理的所有 Target 集合
    • RequestTarcker 是所有 Request 的集合,

搬运地址:

Glide4.0源码全解析(一), GlideAPP 和.with()方法背后的故事

Glide4.0源码全解析(二), load() 背后的故事

Glide源码解析(三)

Android图片加载库 Glide 知其然知其所以然 开篇

Android 图片加载库 Glide 知其然知其所以然之加载

Glide架构设计艺术

Glide源码导读