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")@NonNullpublic <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 perffor (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);}@NonNullpublic synchronized List<Class<?>> getDataClasses(@NonNull Class<?> modelClass) {return multiModelLoaderFactory.getDataClasses(modelClass);}@NonNullprivate 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<>();@SyntheticModelLoaderCache() {}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@Overridepublic ModelLoader<String, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {return new StringLoader<>(multiFactory.build(Uri.class, InputStream.class));}@Overridepublic 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@Overridepublic 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
@Overridepublic 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 perffor (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方法
@Overridepublic 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 perffor (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 perffor (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);}@VisibleForTestingMultiModelLoaderFactory(@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);}@NonNullsynchronized <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;}@NonNullsynchronized <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中返回*/@NonNullsynchronized <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;}}@NonNullsynchronized 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*/@NonNullpublic 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 {@NonNullpublic <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> {@SyntheticEmptyModelLoader() {}@Nullable@Overridepublic LoadData<Object> buildLoadData(@NonNull Object o, int width, int height, @NonNull Options options) {return null;}@Overridepublic 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@Overridepublic ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) {return new HttpGlideUrlLoader(modelCache);}@Overridepublic 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.*/@Nullablepublic 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的关系、区别
Glide 之 Registry、ModelLoaderRegistry、 MultiModelLoaderFactory、 ModelLoader 分析相关推荐
- Android 图片框架原理——Glide源码分析
目录 前言 一.With() 二.load() 三.into() 1. buildImageViewTarget() 2.关注1 :buildRequest 构建 3.关注2:runRequest 执 ...
- Glide系列(四) — Glide缓存流程分析
文章目录 一.概述 1.1 背景 1.2 系列文章 二.准备知识 2.1 Glide 的缓存分层结构 2.2 Glide 缓存相关类的关联关系 三.缓存的获取流程 3.1 缓存获取的入口 3.2 内存 ...
- Android Glide图片加载框架(二)源码解析之into()
文章目录 一.前言 二.源码解析 1.into(ImageView) 2.GlideContext.buildImageViewTarget() 3.RequestBuilder.into(Targe ...
- Android图片加载框架——Glide(Glide v4)
原文地址 Android图片加载框架--Glide(Glide v4) 前言 android中图片加载框架有很多,所有框架最终达到的目都是在Android平台上以极度简单的方式加载和展示图片,如果我们 ...
- Glide 4.9源码解析-图片加载流程
本文Glide源码基于4.9,版本下载地址如下:Glide 4.9 前言 由于Glide源码真的很复杂,因此本文只分析和贴出与图片加载流程相关的功能以及代码.另外本文Glide源码基于4.9,与3.x ...
- 你真的会使用Glide吗?——Glide的高级用法
今天给大家分享一下Glide的一些使用技巧.Glide应该是Android APP中使用最为广泛的图片加载框架了,如丝般的顺滑滚动以及方便的链式调用为广大开发者所喜爱.但是开发中,我们总能遇上一些不太 ...
- Glide 4.9源码解析-缓存策略
本文Glide源码基于4.9,版本下载地址如下:Glide 4.9 前言 在分析了Glide的图片加载流程后,更加发觉到Glide的强大,于是这篇文章将继续深入分析Glide的缓存策略.不过今天的文章 ...
- Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/53939176 本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭 ...
- Android图片加载框架最全解析(三),深入探究Glide的缓存机制
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/54895665 本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭 ...
最新文章
- 数据库缓存最终一致性的四种方案
- 列表自定义的Type和BaseType参考
- 【解题报告】【HDOJ1392】【Graham凸包】Surround the Trees
- docker运行prometheus
- C#并行编程(3):并行循环
- 正确获取Java事件通知
- 让VS2013支持 C# 6.0 语法
- ES6函数参数的解构赋值,以及2种设置参数默认值方法的区别
- Linux的学习笔记~
- python背单词小程序_python背单词小程序
- 三阶魔方还原步骤图_五阶魔方还原教程——层先法
- Linux系统和UNIX系统简介
- picsart旧版本_picsart 2016旧版本下载-picsart 2016版本下载v5.25.4 安卓中文版-2265安卓网...
- 【WPS表格】快捷键合集(更新中)
- 国家开放大学2021春1315社会调查方法题目
- CSS盒子模型、Boder基础
- WLAN从入门到精通-1
- 三种T检验之间的区别
- monocle安装不成功 想尽各种办法
- 最好用的 20 款数据可视化工具