Glide-源碼分析(二)

前言

前面一篇文章對Glide第一次加載網絡圖片的流程經過源碼的方式一步步的帶你們看了下,至少對Glide的整個框架有了一個大體的認識。這篇文章咱們繼續深刻。java

概要

這一篇主要介紹下,第一次加載圖片緩存磁盤後,從新啓動app,再次加載的時候,從磁盤讀取的過程。中間還會涉及到Glide其餘的一些源碼內容。緩存

正文

從磁盤加載文件,那麼確定就有把圖片存起來的這個步驟。咱們先來看看Glide是如何把圖片存起來的。網絡

上篇文章已經簡單的介紹了,就是圖片加載成功以後從新又調用了SourceGeneratorstartNext方法。app

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行代碼,咱們一個個來解析。ide

  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 類型的。 fetch

image.png

本身debug一下,就會比較清楚,encoders裏面註冊了2個Encoder,分別用來解析ByteBufferInputStreamui

很顯然,這裏返回了StreamEncoder來處理。this

  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

相關文章
相關標籤/搜索