Glide-源码分析(二)

前言

前面一篇文章对Glide第一次加载网络图片的流程通过源码的方式一步步的带大家看了下,至少对Glide的整个框架有了一个大致的认识。这篇文章我们继续深入。

概要

这一篇主要介绍下,第一次加载图片缓存磁盘后,重新启动app,再次加载的时候,从磁盘读取的过程。中间还会涉及到Glide其他的一些源码内容。

正文

从磁盘加载文件,那么肯定就有把图片存起来的这个步骤。我们先来看看Glide是如何把图片存起来的。

上篇文章已经简单的介绍了,就是图片加载成功之后重新又调用了SourceGeneratorstartNext方法。

public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }
...
  }

重点就是看下cacheData这个方法,如何去缓存图片。上一篇文章,重在流程,所以一笔带过了,这次我们就继续深入。

private void cacheData(Object dataToCache) {
    long startTime = LogTime.getLogTime();
    try {
      Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
      DataCacheWriter<Object> writer =
          new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
      originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
      helper.getDiskCache().put(originalKey, writer);
     ...
  }

其实最主要的就是这4行代码,我们一个个来解析。

  1. 获取编码器
<X> Encoder<X> getSourceEncoder(X data) throws Registry.NoSourceEncoderAvailableException {
    return glideContext.getRegistry().getSourceEncoder(data);
  }
...
public <X> Encoder<X> getSourceEncoder(@NonNull X data) throws NoSourceEncoderAvailableException {
    Encoder<X> encoder = encoderRegistry.getEncoder((Class<X>) data.getClass());
    if (encoder != null) {
      return encoder;
    }
    throw new NoSourceEncoderAvailableException(data.getClass());
  }
...
public synchronized <T> Encoder<T> getEncoder(@NonNull Class<T> dataClass) {
    for (Entry<?> entry : encoders) {
      if (entry.handles(dataClass)) {
        return (Encoder<T>) entry.encoder;
      }
    }
    return null;
  }

一步步跟入,就是这3个方法,总结来说,就是一开始的时候在EncoderRegistry对象中注册多个编码器,通过key-value的形式保存起来,可以通过传入的数据类型来获取到自己对应的编码器。

这里就直接说下结果。前面网络请求返回对象是ContentLengthInputStream 类型的。

image.png

自己debug一下,就会比较清楚,encoders里面注册了2个Encoder,分别用来解析ByteBufferInputStream

很显然,这里返回了StreamEncoder来处理。

  1. 创建DataCacheWriter
    把第一步获取到的StreamEncoder当作参数传入。只是创建个对象,没什么好说的。

  2. 创建缓存的DataCacheKey
    key-value的方式缓存数据,这里的key就是DataCacheKey

  3. 缓存数据
    这里就是重点了,开始进行磁盘缓存数据。

helper.getDiskCache().put(originalKey, writer);

首先我们要知道helper.getDiskCache()获取到的对象是什么。因为三方框架中会使用很多接口,所以我们有时间直接看代码并不能马上知道具体对应是哪个实现。
这里有2个办法。

  1. debug跟入直接看
  2. 不停往前找,用ctrl+左键一直往前找引用,找赋值的地方

这里我就不带大家这样一步步找了,直接看关键的几个地方。
DecodeHelper->diskCacheProvider=>
DecodeJob->diskCacheProvider=>
DecodeJobFactory->diskCacheProvider=>
Engine->diskCacheProvider这里就发现了

this.diskCacheProvider = new LazyDiskCacheProvider(diskCacheFactory);

但是这里又有一个参数diskCacheFactory
我们还需要看这个是那里来的,继续往前找
Engine->diskCacheFactory=>
GlideBuilder->diskCacheFactory这里发现了

if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }

在构建Glide对象的时候如果没有传入diskCacheFactory,那么这里就会默认生成一个InternalCacheDiskCacheFactory

好了这样我们就可以重新再来看下

helper.getDiskCache().put(originalKey, writer);

其实就是

  helper.getDiskCache().put(originalKey, writer);
...
DiskCache getDiskCache() {
    return diskCacheProvider.getDiskCache();
  }
...
 @Override
    public DiskCache getDiskCache() {
      if (diskCache == null) {
        synchronized (this) {
          if (diskCache == null) {
            diskCache = factory.build();
          }
          if (diskCache == null) {
            diskCache = new DiskCacheAdapter();
          }
        }
      }
      return diskCache;
    }

前面我们已经一鼓作气,把factory也找出来了,也就是InternalCacheDiskCacheFactory

public final class InternalCacheDiskCacheFactory extends DiskLruCacheFactory

//build方法在DiskLruCacheFactory里面
public DiskCache build() {
    File cacheDir = cacheDirectoryGetter.getCacheDirectory();

    if (cacheDir == null) {
      return null;
    }

    if (!cacheDir.mkdirs() && (!cacheDir.exists() || !cacheDir.isDirectory())) {
      return null;
    }

    return DiskLruCacheWrapper.create(cacheDir, diskCacheSize);
  }

这里就是创建缓存的文件。

public final class InternalCacheDiskCacheFactory extends DiskLruCacheFactory {
    public InternalCacheDiskCacheFactory(Context context) {
        this(context, "image_manager_disk_cache", 262144000L);
    }

    public InternalCacheDiskCacheFactory(Context context, long diskCacheSize) {
        this(context, "image_manager_disk_cache", diskCacheSize);
    }

    public InternalCacheDiskCacheFactory(final Context context, final String diskCacheName, long diskCacheSize) {
        super(new CacheDirectoryGetter() {
            public File getCacheDirectory() {
                File cacheDirectory = context.getCacheDir();
                if (cacheDirectory == null) {
                    return null;
                } else {
                    return diskCacheName != null ? new File(cacheDirectory, diskCacheName) : cacheDirectory;
                }
            }
        }, diskCacheSize);
    }
}

InternalCacheDiskCacheFactory可以看出图片缓存的文件路径。

image.png

就是在context.getCacheDir()里面的image_manager_disk_cache文件夹。
我们可以发现,我这个设备里面已经缓存了一个文件。

如果说,你不想存在这个文件,你就自定义一个DiskLruCacheFactory

在前面我们会发现最后在build方法中创建的是

return DiskLruCacheWrapper.create(cacheDir, diskCacheSize);

一个DiskLruCacheWrapper对象,所以前面缓存的时候也是调用了DiskLruCacheWrapperput方法。

 public void put(Key key, Writer writer) {
        DiskLruCache diskCache = getDiskCache();
        Value current = diskCache.get(safeKey);
        if (current != null) {
          return;
        }
    ...
        DiskLruCache.Editor editor = diskCache.edit(safeKey);
     ...
          File file = editor.getFile(0);
          if (writer.write(file)) {
            editor.commit();
          }
       ...
    } finally {
      writeLocker.release(safeKey);
    }
  }
...
//writer.write
public boolean write(@NonNull File file) {
    return encoder.encode(data, file, options);
  }

DiskLrcCache具体的逻辑这里先不介绍,只要知道了是通过key-value缓存到了本地。后面可以直接通过key获取到缓存的数据。

接下来,我们尝试下,重启App,让Glide从磁盘加载图片。前面的步骤肯定都是一样的。我们就直接从DecodeJobrun方法开始看。

public void run() {
  ...
      runWrapped();
   ...
  }
 private void runWrapped() {
    switch (runReason) {
      case INITIALIZE:
        stage = getNextStage(Stage.INITIALIZE);
        currentGenerator = getNextGenerator();
        runGenerators();
        break;
     ...
    }
  }
private void runGenerators() {
    ...
    while (!isCancelled && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      if (stage == Stage.SOURCE) {
        reschedule();
        return;
      }
    }
    ...
  }

之前是先在ResourceGeneratorDataCacheGenerator里面去找里面的loadData能不能处理这个请求。
在第一次加载网络图片的时候,前面2个都不能处理。但是经过了前面的磁盘缓存后。我们再进入DataCacheGenerator来看下里面的逻辑。

public boolean startNext() {
    while (modelLoaders == null || !hasNextModelLoader()) {
      sourceIdIndex++;
      if (sourceIdIndex >= cacheKeys.size()) {
        return false;
      }

      Key sourceId = cacheKeys.get(sourceIdIndex);
      Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
      cacheFile = helper.getDiskCache().get(originalKey);
      if (cacheFile != null) {
        this.sourceKey = sourceId;
        modelLoaders = helper.getModelLoaders(cacheFile);
        modelLoaderIndex = 0;
      }
    }

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
      loadData =
          modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
              helper.getOptions());
      if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

简单的来讲就是创建了一个DataCacheKey,然后helper.getDiskCache().get获取到缓存的数据。然后再交给对应的loadData去处理。

这里值得注意的是cacheKeysmodelLoaders

我们先来看cacheKeys,一步步往上找
DataCacheGenerator->cacheKeys=>
DecodeHelper->cacheKeys 最终是这里创建的,看下代码

List<Key> getCacheKeys() {
 ...
      List<LoadData<?>> loadData = getLoadData();
      for (int i = 0, size = loadData.size(); i < size; i++) {
        LoadData<?> data = loadData.get(i);
        if (!cacheKeys.contains(data.sourceKey)) {
          cacheKeys.add(data.sourceKey);
        }
         ...
        }
      }
    }
    return cacheKeys;
  }

cacheKeys保存的其实是LoadDatasourceKey.
这里看下List<LoadData<?>>是如何获取到的

 List<LoadData<?>> getLoadData() {
   ...
      List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
      for (int i = 0, size = modelLoaders.size(); i < size; i++) {
        ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
        LoadData<?> current =
            modelLoader.buildLoadData(model, width, height, options);
        if (current != null) {
          loadData.add(current);
        }
      }
    }
    return loadData;
  }

LoadData其实ModelLoader. buildLoadData生成的,所以,我们就继续往下看ModelLoader是哪里来的。

List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);

//Registry.java
public <Model> List<ModelLoader<Model, ?>> getModelLoaders(@NonNull Model model) {
    List<ModelLoader<Model, ?>> result = modelLoaderRegistry.getModelLoaders(model);
   ...
    return result;
  }

//ModelLoadRegistry.java
public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
    List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
  ...
  }

//ModelLoadRegistry.java
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
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;
        }
        if (entry.handles(modelClass)) {
          alreadyUsedEntries.add(entry);
          loaders.add(this.<Model, Object>build(entry));
          alreadyUsedEntries.remove(entry);
        }
      }
      return loaders;
    } catch (Throwable t) {
      alreadyUsedEntries.clear();
      throw t;
    }
  }

路径很深,大家可以直接看MultiModelLoaderFactory.build方法.
值得注意的是这里有个变量是entries,我们看看下是什么东西。

private final List<Entry<?, ?>> entries = new ArrayList<>();

我们使用ctrl+鼠标左键找下引用的地方,看看哪里往里面添加东西了,添加了什么东西。

private <Model, Data> void add(
      @NonNull Class<Model> modelClass,
      @NonNull Class<Data> dataClass,
      @NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory,
      boolean append) {
    Entry<Model, Data> entry = new Entry<>(modelClass, dataClass, factory);
    entries.add(append ? entries.size() : 0, entry);
  }

ctrl+鼠标左键,看哪里调用了add,一步步往上找。

//MultiModelLoaderFactory.java
synchronized <Model, Data> void append(
      @NonNull Class<Model> modelClass,
      @NonNull Class<Data> dataClass,
      @NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory) {
    add(modelClass, dataClass, factory, /*append=*/ true);
  }

//ModelLoaderRegistry.java
 public synchronized <Model, Data> void append(
      @NonNull Class<Model> modelClass,
      @NonNull Class<Data> dataClass,
      @NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory) {
    multiModelLoaderFactory.append(modelClass, dataClass, factory);
    cache.clear();
  }
//Registry.java
 public <Model, Data> Registry append(
      @NonNull Class<Model> modelClass, @NonNull Class<Data> dataClass,
      @NonNull ModelLoaderFactory<Model, Data> factory) {
    modelLoaderRegistry.append(modelClass, dataClass, factory);
    return this;
  }

最终找到,调用的地方是Glide的构造方法。

image.png

由于方法实在是太长了,这里就直接贴出图片。

image.png

我们再来看下方法,注意下参数名。

 public <Model, Data> Registry append(Class<Model> modelClass,  Class<Data> dataClass,
   ModelLoaderFactory<Model, Data> factory) {
    modelLoaderRegistry.append(modelClass, dataClass, factory);
    return this;
  }

modelClass->传入的数据class,这里我们传入的是http字符串,也就是String.class

dataClass->处理后得到的数据class,前面文章介绍了第一次加载图片得到的其实是InputStream的子类

factory->创建处理传入数据是modelClass这种类型,得到数据是dataClass这种类型的处理器的工厂

我们继续回过头看下

 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;
        }
        if (entry.handles(modelClass)) {
          alreadyUsedEntries.add(entry);
          loaders.add(this.<Model, Object>build(entry));
          alreadyUsedEntries.remove(entry);
        }
      }
      return loaders;
    } catch (Throwable t) {
      alreadyUsedEntries.clear();
      throw t;
    }
  }

这里就看起来清晰多了,先调用entry.handles(modelClass)看看这个entry能不能处理modelClass这个类型的请求,如果可以就调用build方法构建一个ModelLoader

我们一步步来,先看handles方法

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

非常简单,就看modelClass是不是之前注册的modelClass的子类。

那么继续看build方法。

private <Model, Data> ModelLoader<Model, Data> build(@NonNull Entry<?, ?> entry) {
    return (ModelLoader<Model, Data>) Preconditions.checkNotNull(entry.factory.build(this));
  }

其实就是调用entry.factory.build(this)。前面已经介绍过了,factory其实就是前面注册的第三个参数。那么我们就可以看看之前,modelClass为String的对应的几个ModelLoaderFactory
根据前面的介绍是在Glide构造函数中添加的。我们就看下具体是哪几个。

.append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
.append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
.append(String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())

所以得到的loaders就是4个上面的factory调用build之后所创建的ModelLoader。这里就以StringLoader.StreamFactory.build方法为例子介绍下.

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

这里就有个比较巧妙的地方,继续调用了multiFactory也就是MultiModelLoaderFactorybuild方法,但是这次和前面不一样,这里传了2个参数,Uri.class对应modelClassInputStream对应dataClass,举一反三。前面已经介绍了传了一个参数,就是找到前面注册的modelClass为String.class的factory。这里也是一样,只不过这里要找到modelClass为Uri.classs,dataClass为InputStream的factory。然后使用factory构建出对应的ModelLoader

这里我们只需要知道,前面创建的StringLoader,内部有一个参数是uriLoader,而这个uriLoader就是处理modelClass为Uri,dataClass为InputStream的ModelLoader。那么我们可以在Glide的构造方法内找一下对应的factory。

.append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
.append(Uri.class, InputStream.class, new AssetUriLoader.StreamFactory(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(contentResolver))
         ...

有点多,我就不一一写出了。

接下来就往前面看。

//ModelLoaderRegistry.java
public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
  //这里获取到了4个
    List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
    int size = modelLoaders.size();
    boolean isEmpty = true;
    List<ModelLoader<A, ?>> filteredLoaders = Collections.emptyList();
    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;
  }

大家可以注意下上面的注释,就是loader.handlers过滤了一个ModelLoader,这里就直接说了,过滤了DataUrlLoader

public boolean handles(@NonNull Model model) {
    return model.toString().startsWith(DATA_SCHEME_IMAGE);
  }

显然我们传入的字符串不是以这个为开头,所以为false。
所以最后传回去的是3个ModelLoader。继续往前看。

List<LoadData<?>> getLoadData() {
    if (!isLoadDataSet) {
      isLoadDataSet = true;
      loadData.clear();
    //这边就是前面得到的3个ModelLoader
      List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
      for (int i = 0, size = modelLoaders.size(); i < size; i++) {
        ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
        LoadData<?> current =
            modelLoader.buildLoadData(model, width, height, options);
        if (current != null) {
          loadData.add(current);
        }
      }
    }
    return loadData;
  }

前面其实已经介绍过了,返回的其实是3个StringLoader,只不过是里面的uriLoader不太一样罢了。

 public LoadData<Data> buildLoadData(@NonNull String model, int width, int height,
      @NonNull Options options) {
    Uri uri = parseUri(model);
    if (uri == null || !uriLoader.handles(uri)) {
      return null;
    }
    return uriLoader.buildLoadData(uri, width, height, options);
  }
...
//MultiModelLoader.java
public boolean handles(@NonNull Model model) {
    for (ModelLoader<Model, Data> modelLoader : modelLoaders) {
      if (modelLoader.handles(model)) {
        return true;
      }
    }
    return false;
  }

uriLoader是一个MultiModelLoader,其实也是遍历一下,看看MultiModelLoader内部的ModelLoader能不能处理。

//HttpUriLoader

  private static final Set<String> SCHEMES =
      Collections.unmodifiableSet(new HashSet<>(Arrays.asList("http", "https")));

public boolean handles(@NonNull Uri model) {
    return SCHEMES.contains(model.getScheme());
  }

找到HttpUriLoader能够处理。然后调用HttpUriLoader.buildLoaderData

 public LoadData<InputStream> buildLoadData(@NonNull Uri model, int width, int height,
      @NonNull Options options) {
    return urlLoader.buildLoadData(new GlideUrl(model.toString()), width, height, options);
  }

这里很奇怪,这里又来了一个urlLoader是什么东西。
创建HttpUriLoader的时候是根据一个factory创建的,

public static class Factory implements ModelLoaderFactory<Uri, InputStream> {
...
    public ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {
      return new HttpUriLoader(multiFactory.build(GlideUrl.class, InputStream.class));
    }
...
  }

这段代码感觉又非常熟悉,跟前面很像,只不过这里的modelClassGlideUrl,dataClassInputStream,我们在Glide构造方法里面找一下

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

就这一个。
所以刚才urlLoader其实就是由HttpGlideUrlLoader.Factory()构建的HttpGlideUrlLoader。那么我们来看下HttpGlideUrlLoader.buildLoadData

public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
      @NonNull Options options) {
GlideUrl url = model;
   ...
    return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
  }

HttpUrlFetcher其实就是真正发起http请求获取数据的fetcher。这里就不在深入了。

这里我们重新再看下这行代码

urlLoader.buildLoadData(new GlideUrl(model.toString()), width, height, options)

我们可以看下GlideUrl

public class GlideUrl implements Key

它实现了Key接口。所以前面获取DiskCacheKey传入的参数其实就是GlideUrl。那么我们就重新再回到最前面。DataCacheGenerator

 public boolean startNext() {
    while (modelLoaders == null || !hasNextModelLoader()) {
     ...
      Key sourceId = cacheKeys.get(sourceIdIndex);
     ...
      Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
      cacheFile = helper.getDiskCache().get(originalKey);
      if (cacheFile != null) {
        this.sourceKey = sourceId;
        modelLoaders = helper.getModelLoaders(cacheFile);
        modelLoaderIndex = 0;
      }
    }

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
      loadData =
          modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
              helper.getOptions());
      if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

经过前面介绍如何获取到ModelLoader已经Key是什么之后,再来看下这段代码,就会发现有不太一样的认识。

cacheFile这里已经不为null。
然后继续往下,从helper.getModelLoaders(cacheFile),其实就是找到modelClassFilefactory

.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, UnitModelLoader.Factory.<File>getInstance())

然后反正就根据我刚才那样一步步往下走就好了,就会找到对应的ModelLoader然后生成对应的LoadData,这里就直接不再跟入了,
这里LoadData其实是ByteBufferFileLoader

private static final class ByteBufferFetcher implements DataFetcher<ByteBuffer> {
...
    @Override
    public void loadData(@NonNull Priority priority,
        @NonNull DataCallback<? super ByteBuffer> callback) {
      ByteBuffer result;
     ...
        result = ByteBufferUtil.fromFile(file);
   ...

      callback.onDataReady(result);
    }

里面的fetcher就是ByteBufferFetcher,然后调用loadData方法读取到数据。

总结

这篇文章主要是对磁盘缓存数据还有获取数据的分析,以及ModelLoader的分析。后续还会继续深入分析Glide

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,454评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,553评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,921评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,648评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,770评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,950评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,090评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,817评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,275评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,592评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,724评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,409评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,052评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,815评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,043评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,503评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,627评论 2 350

推荐阅读更多精彩内容