Glide 之 Registry、ModelLoaderRegistry、 MultiModelLoaderFactory、 ModelLoader 分析

Registry  Manages component registration to extend or replace Glide's default loading, decoding, and encoding logic.

它的主要工作是在Glide初始化的时候做的,我们截取一段代码看看

首先看看ModelLoader相关的

    registry
        .append(int.class, InputStream.class, resourceLoaderStreamFactory)
        .append(int.class, ParcelFileDescriptor.class, resourceLoaderFileDescriptorFactory)
        .append(Integer.class, InputStream.class, resourceLoaderStreamFactory)
        .append(Integer.class, ParcelFileDescriptor.class, resourceLoaderFileDescriptorFactory)
        .append(Integer.class, Uri.class, resourceLoaderUriFactory)
        .append(int.class, AssetFileDescriptor.class, resourceLoaderAssetFileDescriptorFactory)
        .append(Integer.class, AssetFileDescriptor.class, resourceLoaderAssetFileDescriptorFactory)
        .append(int.class, Uri.class, resourceLoaderUriFactory)
        .append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
        .append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
        //注意看modelClass 是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())

分析append方法:

  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;
  }

直接调用了ModeLoaderRegistry的append方法:

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

在ModelLoaderRegistry中封装了了一个MultiModelLoaderFactory,MultiModelLoaderFactory里面有一个List,append进来的都最终放到了这个list中,cache只是为了提高效率缓存。具体看ModelLoaderRegistry和MultiModelLoaderFactory源码,关键方法进行了注释。

Registry的append方法没什么难度,这个是放进去,那么我们怎么取出来了呢?

这个就是Registry的getModelLoaders方法,根据Model类型来获取一个ModelLoader的List。可以看ModelLoaderRegistry的源码,有注释。

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

ModelLoaderRegistry

package com.bumptech.glide.load.model;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pools.Pool;
import com.bumptech.glide.Registry.NoModelLoaderAvailableException;
import com.bumptech.glide.util.Synthetic;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Maintains an ordered put of {@link ModelLoader}s and the model and data types they handle in
 * order from highest priority to lowest.
 */
// Hides Model throughout.
@SuppressWarnings("TypeParameterHidesVisibleType")
public class ModelLoaderRegistry {

  private final MultiModelLoaderFactory multiModelLoaderFactory;
  private final ModelLoaderCache cache = new ModelLoaderCache();

  public ModelLoaderRegistry(@NonNull Pool<List<Throwable>> throwableListPool) {
    this(new MultiModelLoaderFactory(throwableListPool));
  }

  private ModelLoaderRegistry(@NonNull MultiModelLoaderFactory multiModelLoaderFactory) {
    this.multiModelLoaderFactory = multiModelLoaderFactory;
  }

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

  public synchronized <Model, Data> void prepend(
      @NonNull Class<Model> modelClass,
      @NonNull Class<Data> dataClass,
      @NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory) {
    multiModelLoaderFactory.prepend(modelClass, dataClass, factory);
    cache.clear();
  }

  public synchronized <Model, Data> void remove(
      @NonNull Class<Model> modelClass, @NonNull Class<Data> dataClass) {
    tearDown(multiModelLoaderFactory.remove(modelClass, dataClass));
    cache.clear();
  }

  public synchronized <Model, Data> void replace(
      @NonNull Class<Model> modelClass,
      @NonNull Class<Data> dataClass,
      @NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory) {
    tearDown(multiModelLoaderFactory.replace(modelClass, dataClass, factory));
    cache.clear();
  }

  private <Model, Data> void tearDown(
      @NonNull List<ModelLoaderFactory<? extends Model, ? extends Data>> factories) {
    for (ModelLoaderFactory<? extends Model, ? extends Data> factory : factories) {
      factory.teardown();
    }
  }

  // We're allocating in a loop to avoid allocating empty lists that will never have anything added
  // to them.
  @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
  @NonNull
  public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
    List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
    if (modelLoaders.isEmpty()) {
      throw new NoModelLoaderAvailableException(model);
    }
    int size = modelLoaders.size();
    boolean isEmpty = true;
    List<ModelLoader<A, ?>> filteredLoaders = Collections.emptyList();
    /*
     *下面这条注释的意思
     * https://stackoverflow.com/questions/17836373/what-does-noinspection-forloopreplaceablebyforeach-mean
     */
    //noinspection ForLoopReplaceableByForEach to improve perf
    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);
      }
    }
    if (filteredLoaders.isEmpty()) {
      throw new NoModelLoaderAvailableException(model, modelLoaders);
    }
    return filteredLoaders;
  }

  public synchronized <Model, Data> ModelLoader<Model, Data> build(
      @NonNull Class<Model> modelClass, @NonNull Class<Data> dataClass) {
    return multiModelLoaderFactory.build(modelClass, dataClass);
  }

  @NonNull
  public synchronized List<Class<?>> getDataClasses(@NonNull Class<?> modelClass) {
    return multiModelLoaderFactory.getDataClasses(modelClass);
  }

  @NonNull
  private synchronized <A> List<ModelLoader<A, ?>> getModelLoadersForClass(
      @NonNull Class<A> modelClass) {
    //这块又用到了缓存思想,如果没有新的modelClass添加,cache中的就是需要的
    //如果,不从缓存中取,就需要调用multiModelLoaderFactory的build,这样的化,就可能会实例化多个ModelLoader,开销会很大
    List<ModelLoader<A, ?>> loaders = cache.get(modelClass);
    if (loaders == null) {
      loaders = Collections.unmodifiableList(multiModelLoaderFactory.build(modelClass));
      cache.put(modelClass, loaders);
    }
    return loaders;
  }

  @NonNull
  @SuppressWarnings("unchecked")
  private static <A> Class<A> getClass(@NonNull A model) {
    return (Class<A>) model.getClass();
  }

  private static class ModelLoaderCache {
    private final Map<Class<?>, Entry<?>> cachedModelLoaders = new HashMap<>();

    @Synthetic
    ModelLoaderCache() {}

    public void clear() {
      cachedModelLoaders.clear();
    }

    public <Model> void put(Class<Model> modelClass, List<ModelLoader<Model, ?>> loaders) {
      Entry<?> previous = cachedModelLoaders.put(modelClass, new Entry<>(loaders));
      if (previous != null) {
        throw new IllegalStateException("Already cached loaders for model: " + modelClass);
      }
    }

    @Nullable
    @SuppressWarnings("unchecked")
    public <Model> List<ModelLoader<Model, ?>> get(Class<Model> modelClass) {
      Entry<Model> entry = (Entry<Model>) cachedModelLoaders.get(modelClass);
      return entry == null ? null : entry.loaders;
    }

    private static class Entry<Model> {
      @Synthetic final List<ModelLoader<Model, ?>> loaders;

      public Entry(List<ModelLoader<Model, ?>> loaders) {
        this.loaders = loaders;
      }
    }
  }
}

MultiModelLoaderFactory是一个很重要的类,首先它存储了所有了modelClass、dataClass和ModelLoaderFactory的信息,在entries List里面。还有两个很重要的重载方法load。

synchronized <Model> List<ModelLoader<Model, ?>> build(@NonNull Class<Model> modelClass)

根据modelClass类型,把所有entries List中的所有modelClass类型的ModelLoader都通过工厂类ModelLoaderFactory方法build出来,并放到loaders List中返回。

需要说明的是不同的ModelLoaderFactory的build实现是不同的,build方法中传入的MultiModelLoaderFactory对象。

具体分析一个例子,我们看看StringLoader的工厂类,从类名我们也知道这个ModelLoader的modelClass是String,由于dataClass可以有很多种(InputStream、ParcelFileDescriptor、AssetFileDescriptor),所以也有很多种Factory,比如我们要分析的StreamFactory

  /** Factory for loading {@link InputStream}s from Strings. */
  public static class StreamFactory implements ModelLoaderFactory<String, InputStream> {

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

    @Override
    public void teardown() {
      // Do nothing.
    }
  }

先看看StringLoader.StreamFactory的注册调用

.append(String.class, InputStream.class, new StringLoader.StreamFactory())

我们知道在MultiModelLoaderFactory的load方法中传入的是String.class,在迭代entries的时候,肯定会调用到StringLoader.StreamFactory的load方法,也就是上面的方法。重点来了

return new StringLoader<>(multiFactory.build(Uri.class, InputStream.class));

这里new一个StringLoader实例没有问题,问题是StringLoader里面包装了一个MutilModelLoader对象,而这个对象是由MultiModelLoaderFactory的重载的load方法返回的。

public synchronized <Model, Data> ModelLoader<Model, Data> build(
    @NonNull Class<Model> modelClass, @NonNull Class<Data> dataClass)

这个loader方法和上一个load主要逻辑是一致的,把modelClass和dataClass对应的ModelLoader通过Factory时候化出来,唯一区别是,把这些ModelLoader封装成一个MultiModelLoader,MultiModelLoader也是ModelLoader,它只是把modelClass相同,同时dataClass相同的ModelLoader封装到一个MultiModelLoader里面。

第一个build只有一个调用入口,ModelLoaderRegistry的getModelLoadersForClass方法,这是一个私有方法(这个方法里面加了一层缓存,看代码注释),被对外暴露的getModelLoaders方法调用,这个方法里面还需要进行一次校验,把无效的ModelLoader去掉。ModelLoaderRegistry的getModelLoaders方法被Registry的getModelLoaders方法调用。Registry的getModelLoaders就是业务逻辑中要用到的接口啦

下面我们以具体例子,调试分析一下

        ImageView glide_image_view = findViewById(R.id.glide_image_view);
        String str = "https://photocdn.tv.sohu.com/img/20161013/vrs_1476350821000_85454913_4wX29_pic6.jpg";
        Glide.with(this).load(str).into(glide_image_view);

从上面代码看,我们知道modelClass是String,这个也是我们最常用的方式

从DecodeHelper的getLoadData直接调用到MultiModelLoaderFactory的build(Class<Model> modelClass)方法

entries list里面存了所有注册进来的<modelClass, dataClass, factory>,有35个,我们要找到modelClass是String的,我们分析一个factory是StringLoader.StreamFactory的build,它会调用到MultiModelLoaderFactory 的build( @NonNull Class<Model> modelClass, @NonNull Class<Data> dataClass)

这个就是把modelClass是Uri,dataClass是InputStream,对应的所有ModelLoader包装成一个MultiModelLoader,然后再包装到StringLoader里面

看上图,这个loaders返回到ModelLoaderRegistry的getModelLoadersForClass方法进行缓存,在getModelLoaders中过滤无效的。是否有效通过ModelLoader的handle方法来判断的

DataUrlLoader的handle方法,返回fasle
  @Override
  public boolean handles(@NonNull Model model) {
    // We expect Model to be a Uri or a String, both of which implement toString() efficiently. We
    // should reconsider this implementation before adding any new Model types.
    return model.toString().startsWith(DATA_SCHEME_IMAGE);
  }
//StringLoader 的handle方法返回true  
@Override
  public boolean handles(@NonNull String model) {
    // Avoid parsing the Uri twice and simply return null from buildLoadData if we don't handle this
    // particular Uri type.
    return true;
  }

我们接着看看DecodeHelper的getLoadData方法

  List<LoadData<?>> getLoadData() {
    if (!isLoadDataSet) {
      isLoadDataSet = true;
      loadData.clear();
      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);
        LoadData<?> current =
            modelLoader.buildLoadData(model, width, height, options);
        if (current != null) {
          loadData.add(current);
        }
      }
    }
    return loadData;
  }

 glideContext.getRegistry().getModelLoaders(model)上面已经分析过了,就是根据model的类型(比如String)获取一个能处理model类型的ModelLoader的列表。ModelLoader是一个工厂接口,它能把任意的数据model转化成DataFetcher能使用具体数据类型,通过buildLoadData方法完成,看个例子

我们现在知道modelLoaders的size是3,get(0)是个StringLoader,里面封装了7个loader,StringLoader是个MultiModelLoader,看看它的buildLoadData方法

  @Override
  public LoadData<Data> buildLoadData(@NonNull Model model, int width, int height,
      @NonNull Options options) {
    Key sourceKey = null;
    int size = modelLoaders.size();
    List<DataFetcher<Data>> fetchers = new ArrayList<>(size);
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0; i < size; i++) {
      ModelLoader<Model, Data> modelLoader = modelLoaders.get(i);
      if (modelLoader.handles(model)) {
        LoadData<Data> loadData = modelLoader.buildLoadData(model, width, height, options);
        if (loadData != null) {
          sourceKey = loadData.sourceKey;
          fetchers.add(loadData.fetcher);
        }
      }
    }
    return !fetchers.isEmpty() && sourceKey != null
        ? new LoadData<>(sourceKey, new MultiFetcher<>(fetchers, exceptionListPool)) : null;
  }

很简单,就是把7个loader遍历一遍,求得的LoadData们,组装成一个新的LoadData,我们知道七个中有一个是HttpUriLoader,执行buildLoadData方法

@Override
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是HttpGlideUrlLoader

@Override
public LoadData<InputStream> buildLoadData(
    @NonNull GlideUrl model, int width, int height, @NonNull Options options) {
  // GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
  // spent parsing urls.
  GlideUrl url = model;
  if (modelCache != null) {
    url = modelCache.get(model, 0, 0);
    if (url == null) {
      modelCache.put(model, 0, 0, model);
      url = model;
    }
  }
  int timeout = options.get(TIMEOUT);
  return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}

看到没,通过一系列的调用下来,model是String类型,被转换成了GlideUrl类型,这个类型是被HttpUrlFetcher使用的,统一被封装到了LoadData里面。现在再来体会一些对ModelLoader的解释。

如下图

看到没这个loadData中是一个MultiFetcher 里面有两HttpUrlFetcher

get(1)和get(2)的StringLoader都不会生成LoadData。

总结一下,getLoadData返回的loadData list中只有一个LoadData实例,sourceKey是地址封装成的GlideUrl,fetcher是个MultiFetcher包含了两个HttpUrlFetcher。

看看DecodeHelper 的getCacheKeys方法

  List<Key> getCacheKeys() {
    if (!isCacheKeysSet) {
      isCacheKeysSet = true;
      cacheKeys.clear();
      List<LoadData<?>> loadData = getLoadData();
      //noinspection ForLoopReplaceableByForEach to improve perf
      for (int i = 0, size = loadData.size(); i < size; i++) {
        LoadData<?> data = loadData.get(i);
        if (!cacheKeys.contains(data.sourceKey)) {
          cacheKeys.add(data.sourceKey);
        }
        for (int j = 0; j < data.alternateKeys.size(); j++) {
          if (!cacheKeys.contains(data.alternateKeys.get(j))) {
            cacheKeys.add(data.alternateKeys.get(j));
          }
        }
      }
    }
    return cacheKeys;
  }

其实就是把loadData 数组中每个LoadData的sourceKey取出来给缓存到cacheKeys里面

MultiModelLoaderFactory

package com.bumptech.glide.load.model;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.util.Pools.Pool;
import com.bumptech.glide.Registry.NoModelLoaderAvailableException;
import com.bumptech.glide.load.Options;
import com.bumptech.glide.util.Preconditions;
import com.bumptech.glide.util.Synthetic;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * Capable of building an {@link ModelLoader} that wraps one or more other {@link ModelLoader}s for
 * a given model and data class.
 */
// Hides Model throughout.
@SuppressWarnings("TypeParameterHidesVisibleType")
public class MultiModelLoaderFactory {
  private static final Factory DEFAULT_FACTORY = new Factory();
  private static final ModelLoader<Object, Object> EMPTY_MODEL_LOADER = new EmptyModelLoader();
  private final List<Entry<?, ?>> entries = new ArrayList<>();
  private final Factory factory;
  private final Set<Entry<?, ?>> alreadyUsedEntries = new HashSet<>();
  private final Pool<List<Throwable>> throwableListPool;

  public MultiModelLoaderFactory(@NonNull Pool<List<Throwable>> throwableListPool) {
    this(throwableListPool, DEFAULT_FACTORY);
  }

  @VisibleForTesting
  MultiModelLoaderFactory(
      @NonNull Pool<List<Throwable>> throwableListPool, @NonNull Factory factory) {
    this.throwableListPool = throwableListPool;
    this.factory = factory;
  }

  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);
  }

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

  /*
   * 不同类型的modelClass、dataClass和ModeLoaderFactory都会被打包成Entry放到List中
   *
   *
   */
  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);
  }

  @NonNull
  synchronized <Model, Data> List<ModelLoaderFactory<? extends Model, ? extends Data>> replace(
      @NonNull Class<Model> modelClass,
      @NonNull Class<Data> dataClass,
      @NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory) {
    List<ModelLoaderFactory<? extends Model, ? extends Data>> removed =
        remove(modelClass, dataClass);
    append(modelClass, dataClass, factory);
    return removed;
  }

  @NonNull
  synchronized <Model, Data> List<ModelLoaderFactory<? extends Model, ? extends Data>> remove(
      @NonNull Class<Model> modelClass, @NonNull Class<Data> dataClass) {
    List<ModelLoaderFactory<? extends Model, ? extends Data>> factories = new ArrayList<>();
    for (Iterator<Entry<?, ?>> iterator = entries.iterator(); iterator.hasNext(); ) {
      Entry<?, ?> entry = iterator.next();
      if (entry.handles(modelClass, dataClass)) {
        iterator.remove();
        factories.add(this.<Model, Data>getFactory(entry));
      }
    }
    return factories;
  }

  /*
   *
   * 根据modelClass类型,把所有entries List中的所有modelClass类型的ModelLoader都通过工厂方法build出来,
   * 并放到loaders List中返回
   */
  @NonNull
  synchronized <Model> List<ModelLoader<Model, ?>> build(@NonNull Class<Model> modelClass) {
    try {
      List<ModelLoader<Model, ?>> loaders = new ArrayList<>();
      for (Entry<?, ?> entry : entries) {
        // Avoid stack overflow recursively creating model loaders by only creating loaders in
        // recursive requests if they haven't been created earlier in the chain. For example:
        // A Uri loader may translate to another model, which in turn may translate back to a Uri.
        // The original Uri loader won't be provided to the intermediate model loader, although
        // other Uri loaders will be.
        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;
    }
  }

  @NonNull
  synchronized List<Class<?>> getDataClasses(@NonNull Class<?> modelClass) {
    List<Class<?>> result = new ArrayList<>();
    for (Entry<?, ?> entry : entries) {
      if (!result.contains(entry.dataClass) && entry.handles(modelClass)) {
        result.add(entry.dataClass);
      }
    }
    return result;
  }

  /*
   *
   * 根据modelClass类型和dataClass类型,把所有entries List中的所有modelClass类型同时是dataClasse类型的ModelLoader都通过工厂方法build出来,
   * 并放到loaders List中,如果List size大于1,构造一个MultiModelLoader,并返回
   *
   * 这个引入了MultiModelLoader,它也是一个ModelLoader,只是封装了多个ModelLoader。也就是为啥这个类叫MultiModelLoaderFactory
   */
  @NonNull
  public synchronized <Model, Data> ModelLoader<Model, Data> build(
      @NonNull Class<Model> modelClass, @NonNull Class<Data> dataClass) {
    try {
      List<ModelLoader<Model, Data>> loaders = new ArrayList<>();
      boolean ignoredAnyEntries = false;
      for (Entry<?, ?> entry : entries) {
        // Avoid stack overflow recursively creating model loaders by only creating loaders in
        // recursive requests if they haven't been created earlier in the chain. For example:
        // A Uri loader may translate to another model, which in turn may translate back to a Uri.
        // The original Uri loader won't be provided to the intermediate model loader, although
        // other Uri loaders will be.
        if (alreadyUsedEntries.contains(entry)) {
          ignoredAnyEntries = true;
          continue;
        }
        if (entry.handles(modelClass, dataClass)) {
          alreadyUsedEntries.add(entry);
          loaders.add(this.<Model, Data>build(entry));
          alreadyUsedEntries.remove(entry);
        }
      }
      if (loaders.size() > 1) {
        return factory.build(loaders, throwableListPool);
      } else if (loaders.size() == 1) {
        return loaders.get(0);
      } else {
        // Avoid crashing if recursion results in no loaders available. The assertion is supposed to
        // catch completely unhandled types, recursion may mean a subtype isn't handled somewhere
        // down the stack, which is often ok.
        if (ignoredAnyEntries) {
          return emptyModelLoader();
        } else {
          throw new NoModelLoaderAvailableException(modelClass, dataClass);
        }
      }
    } catch (Throwable t) {
      alreadyUsedEntries.clear();
      throw t;
    }
  }

  @NonNull
  @SuppressWarnings("unchecked")
  private <Model, Data> ModelLoaderFactory<Model, Data> getFactory(@NonNull Entry<?, ?> entry) {
    return (ModelLoaderFactory<Model, Data>) entry.factory;
  }

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

  @NonNull
  @SuppressWarnings("unchecked")
  private static <Model, Data> ModelLoader<Model, Data> emptyModelLoader() {
    return (ModelLoader<Model, Data>) EMPTY_MODEL_LOADER;
  }

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

    public Entry(
        @NonNull Class<Model> modelClass,
        @NonNull Class<Data> dataClass,
        @NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory) {
      this.modelClass = modelClass;
      this.dataClass = dataClass;
      this.factory = factory;
    }

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

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

  static class Factory {
    @NonNull
    public <Model, Data> MultiModelLoader<Model, Data> build(
        @NonNull List<ModelLoader<Model, Data>> modelLoaders,
        @NonNull Pool<List<Throwable>> throwableListPool) {
      return new MultiModelLoader<>(modelLoaders, throwableListPool);
    }
  }

  private static class EmptyModelLoader implements ModelLoader<Object, Object> {
    @Synthetic
    EmptyModelLoader() {}

    @Nullable
    @Override
    public LoadData<Object> buildLoadData(
        @NonNull Object o, int width, int height, @NonNull Options options) {
      return null;
    }

    @Override
    public boolean handles(@NonNull Object o) {
      return false;
    }
  }
}

分析一下ModelLoader相关的代码

ModelLoader是一个工厂接口,HttpGlideUrlLoader是其中实现的一个子类,对这个子类进行分析

glide里面好多对象都是通过工厂类或者接口创建处理的,这种设计模式和采用原因,以后分析

  /**
   * The default factory for {@link HttpGlideUrlLoader}s.
   */
  public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
    private final ModelCache<GlideUrl, GlideUrl> modelCache = new ModelCache<>(500);

    @NonNull
    @Override
    public ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) {
      return new HttpGlideUrlLoader(modelCache);
    }

    @Override
    public void teardown() {
      // Do nothing.
    }
  }

通过一个工厂类,创建一个HttpGlideUrlLoader对象,需要传入一个ModelCache对象,分析一个这个ModelCache类

ModelCache里面封装了LruCache(需要研读LruCache代码),LruCache采用最近最少使用算法,存放key-value。在ModelCache中,key是ModelKey(ModelKey是ModelCache的嵌套类),ModelKey就是存了model、width和height而已,在HttpGlideUrlLoader中model的类型是GlideUrl,value类型也是GlideUrl。

我们可以直观的感受到ModelCache对外暴露的接口功能是从LruCache中存取,实际也是如此:


  
  /**
   * Add a value.
   *
   * @param model  The model.
   * @param width  The width in pixels of the view the image is being loaded into.
   * @param height The height in pixels of the view the image is being loaded into.
   * @param value  The value to store.
   */
  public void put(A model, int width, int height, B value) {
    ModelKey<A> key = ModelKey.get(model, width, height);
    cache.put(key, value);
  }

   /**
   * Get a value.
   *
   * @param model  The model.
   * @param width  The width in pixels of the view the image is being loaded into.
   * @param height The height in pixels of the view the image is being loaded into.
   * @return The cached result, or null.
   */
  @Nullable
  public B get(A model, int width, int height) {
    ModelKey<A> key = ModelKey.get(model, width, height);
    B result = cache.get(key);
    key.release();
    return result;
  }

我们思考一个问题:在我们实际开发中,从Map中存取的话,key一般是什么类型的?答案是不是String比较多。

可是我们看看上面分析的代码,key是什么?key是一个自己定义的类ModelKey,一个复杂的对象。

如果key是String的话,我们潜意识的就是知道只要内容一样,key就一样,就能在map中存取了,这个其实是String重写的hashCode和equals方法保证的。

现在的问题是,我们的key是自定义的ModelKey类型,为了能保证我们new的key对象和Map中的key对象相等,我们也需要重写ModelKey的hashCode和equals方法。看看ModelKey的源码确实是这样。

java基础 equals和hashCode、HashMap

还有另外一个问题:我们map(LruCache)中通过key存取时,每次是不是都得new ModelKey实例呢?创建对象是很消耗性能的,Glide对此做了优化,其实说来也简单,就是做个对象池,把用过的对象key缓存起来,这样的话需要key的话,就从这个对象池中取,把里面的内容改一下就行了。LruCache采用LRU算法,在清理的时候,把key保存到对象池中。对象池的实现方案很多,可以采用Queue也可是采用链表List,在这里采用了Queue,在ModelKey维护了一个静态Queue用作对象池。

现在再看ModelCache的get和set方法就明白了呢?ModelKey<A> key = ModelKey.get(model, width, height);是从对象池中取key,key.release();是把这个key对象放到对象池中。

现在ModelCache分析完了,该回到主线HttpGlideUrlLoader类了,它实现了ModelLoader接口,这个接口里面定义了一个LoadData的数据结构,通过buildLoadData方法把任意复杂的数据类型,比如Url、File,转换成包装后的LoadData,同时这个LoadData对象中还包含了DataFetcher对象。

我们再分析一下DataFetcher

DataFetcher中loadData方法去真正请求数据,HttpUrlFetcher中是通过HttpURLConnection去获取网络数据的。

Glide4.8源码拆解(三)Registry和数据转换流程

数据加载DataFetcher与ModelLoader结构

java.util.Collections类——emptyList()方法

MessageDigest来实现数据加密

Android Bitmap(位图)详解

Bitmap和Drawable的关系、区别
 

发布了189 篇原创文章 · 获赞 25 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/lizhongyisailang/article/details/104117148
今日推荐