DecodeHelper類中丐重,調(diào)用的方法腔召,涉及到的東西比較多,最主要的是包括管理組件注冊以擴展或替換Glide的默認加載扮惦,解碼和編碼邏輯的Registry類臀蛛。在Glide類的構(gòu)造方法中,如下:
Glide(
@NonNull Context context,
@NonNull Engine engine,
@NonNull MemoryCache memoryCache,
@NonNull BitmapPool bitmapPool,
@NonNull ArrayPool arrayPool,
@NonNull RequestManagerRetriever requestManagerRetriever,
@NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
int logLevel,
@NonNull RequestOptions defaultRequestOptions,
@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions) {
....
registry
.append(ByteBuffer.class, new ByteBufferEncoder())
.append(InputStream.class, new StreamEncoder(arrayPool))
/* Bitmaps */
....
.append(int.class, Uri.class, resourceLoaderUriFactory)
.append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
.append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
.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(Uri.class, InputStream.class, new HttpUriLoader.Factory())
.append(Uri.class, InputStream.class, new AssetUriLoader.StreamFactory(context.getAssets()))
.append(
Uri.class,
ParcelFileDescriptor.class,
new AssetUriLoader.FileDescriptorFactory(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))
....
在這里崖蜜,注冊了一系列的信息浊仆,我們這里著手關(guān)注String.class這塊的ModelLoader對象。一般Glide加載一個url字符串的時候豫领,就是通過String.class取對應(yīng)的ModelLoader對象抡柿。
.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())
最終就是往MultiModelLoaderFactory的成員變量entries加入了四條數(shù)據(jù),Entry的結(jié)構(gòu)如下:
private static class Entry<Model, Data> {
private final Class<Model> modelClass;
@Synthetic final Class<Data> dataClass;
@Synthetic final ModelLoaderFactory<? extends Model, ? extends Data> factory;
}
暫且先有點這個印象等恐,注冊的過程不是我們要重點關(guān)注的洲劣,Registry不過只是一種構(gòu)造ModelLoader的實現(xiàn)而已备蚓,下面我們先分析DecodeHelper的getLoadData的實現(xiàn)。
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;
}
這里的model是一個Object對象囱稽,對于我們的簡單url請求來說郊尝,它就是一個String類對象。通過代碼追蹤战惊,getModelLoaders方法流昏,會返回一個ModelLoader的List,它的實現(xiàn)如下:
public <Model> List<ModelLoader<Model, ?>> getModelLoaders(@NonNull Model model) {
List<ModelLoader<Model, ?>> result = modelLoaderRegistry.getModelLoaders(model);
if (result.isEmpty()) {
throw new NoModelLoaderAvailableException(model);
}
return result;
}
繼續(xù)跟進ModelLoaderRegistry的getModelLoaders,
public synchronized <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
int size = modelLoaders.size();
List<ModelLoader<A, ?>> filteredLoaders = new ArrayList<>(size);
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0; i < size; i++) {
ModelLoader<A, ?> loader = modelLoaders.get(i);
if (loader.handles(model)) {
filteredLoaders.add(loader);
}
}
return filteredLoaders;
}
先是調(diào)用取model的class類型吞获,然后通過getModelLoadersForClass去獲取前面注冊進去的loaders信息况凉。獲取到之后,通過ModelLoader的handles方法進行一次過濾各拷。最終返回茎刚,我們繼續(xù)分析getModelLoadersForClass。
private <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.build方法返回值決定的。下面繼續(xù)分析這個方法粮坞。
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;
}
}
Entry我們上面已經(jīng)有所介紹蚊荣,和String有關(guān)的目前有四個,重點就是entry.handles方法的返回值莫杈,決定其是否能加入到loaders中互例,而在這個方法中,實現(xiàn)就是看是否和modelClass能夠匹配筝闹,所以此時和String.class能匹配的就是上面已經(jīng)列出的媳叨。
.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())
接下來會調(diào)用build方法傳入entry獲取一個ModelLoader對象,build實現(xiàn)如下:
private <Model, Data> ModelLoader<Model, Data> build(@NonNull Entry<?, ?> entry) {
return (ModelLoader<Model, Data>) Preconditions.checkNotNull(entry.factory.build(this));
}
這里就是調(diào)用entry對應(yīng)的factory對象去構(gòu)建ModelLoader关顷。這里四個工廠分別是DataUrlLoader.StreamFactory糊秆、StringLoader.StreamFactory、StringLoader.FileDescriptorFactory與StringLoader.AssetFileDescriptorFactory议双。分別構(gòu)造了DataUrlLoader痘番、StringLoader、StringLoader平痰、StringLoader四個loader對象汞舱。
對于一個url,這里我們的是:"https://p.upyun.com/docs/cloud/demo.jpg",ModelLoader中有一個handles方法宗雇,表明此類型是否可以被自己處理昂芜。
DataUrlLoader的實現(xiàn)如下:
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);
}
其中DATA_SCHEME_IMAGE為"data:image",顯然此時不能處理我們的url赔蒲。
StringLoader的實現(xiàn)如下:
public boolean handles(@NonNull String model) {
return true;
}
顯然此時泌神,是可以處理這個url對象的良漱。 三個Factory的build方法的實現(xiàn)如下:
public static class StreamFactory implements ModelLoaderFactory<String, InputStream> {
@NonNull
@Override
public ModelLoader<String, InputStream> build(MultiModelLoaderFactory multiFactory) {
return new StringLoader<>(multiFactory.build(Uri.class, InputStream.class));
}
}
/**
* Factory for loading {@link ParcelFileDescriptor}s from Strings.
*/
public static class FileDescriptorFactory
implements ModelLoaderFactory<String, ParcelFileDescriptor> {
@NonNull
@Override
public ModelLoader<String, ParcelFileDescriptor> build(MultiModelLoaderFactory multiFactory) {
return new StringLoader<>(multiFactory.build(Uri.class, ParcelFileDescriptor.class));
}
}
/**
* Loads {@link AssetFileDescriptor}s from Strings.
*/
public static final class AssetFileDescriptorFactory
implements ModelLoaderFactory<String, AssetFileDescriptor> {
@Override
public ModelLoader<String, AssetFileDescriptor> build(MultiModelLoaderFactory multiFactory) {
return new StringLoader<>(multiFactory.build(Uri.class, AssetFileDescriptor.class));
}
}
這塊相對有點復(fù)雜,在StringLoader中有一個成員變量uriLoader腻扇,它也是由entry傳入的MultiModelLoaderFactory的build方法繼續(xù)創(chuàng)建的债热。這里我們可以看到有一個遞歸的過程,其實也很好理解幼苛,雖然三個都是StringLoader窒篱,但內(nèi)部的成員變量uriLoader不一樣。分別是三對:
- Uri.class, InputStream.class
- Uri.class, ParcelFileDescriptor.class
- Uri.class, AssetFileDescriptor.class
這里其實和之前的邏輯類似舶沿,也是從glide中查表墙杯,繼續(xù)看關(guān)于這三對的注冊情況。仍然是在Glide構(gòu)造方法中注冊的括荡。
- Uri.class, InputStream.class
.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))
.append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory())
- Uri.class, ParcelFileDescriptor.class
.append(Uri.class, ParcelFileDescriptor.class, new AssetUriLoader.FileDescriptorFactory(context.getAssets()))
.append(Uri.class, ParcelFileDescriptor.class, new UriLoader.FileDescriptorFactory(contentResolver))
- Uri.class, AssetFileDescriptor.class
.append(Uri.class,AssetFileDescriptor.class,
new UriLoader.AssetFileDescriptorFactory(contentResolver))
因此高镐,上面三個StringLoader中,成員變量uriLoader分別為:
-
Uri.class, InputStream.class
MultiModelLoader:
[DataUrlLoader畸冲、HttpUriLoader嫉髓、AssetUriLoader、MediaStoreImageThumbLoader邑闲、MediaStoreVideoThumbLoader算行、UriLoader、UrlUriLoader] Uri.class, ParcelFileDescriptor.class -> MultiModelLoader
MultiModelLoader:
[AssetUriLoader苫耸、UriLoader]
- Uri.class, AssetFileDescriptor.class
UriLoader
ModelLoader最重要的功能就是通過buildLoadData創(chuàng)建相應(yīng)的LoadData對象州邢。
MultiModelLoader實現(xiàn)如下:
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;
}
對于我們的三種情況來講,考慮到handles的過濾褪子,model是"https://p.upyun.com/docs/cloud/demo.jpg"量淌,因此最終創(chuàng)建的LoadData的fetchers信息如下:
- Uri.class, InputStream.class
LoadData: [{GlideUrl, HttpUrlFetcher},{GlideUrl, HttpUrlFetcher}]
- Uri.class, ParcelFileDescriptor.class -> MultiModelLoader
LoadData: []
- Uri.class, AssetFileDescriptor.class
LoadData:[{ObjectKey, AssetFileDescriptorLocalUriFetcher}]
至此返回的三個StringLoader以及最終創(chuàng)建的LoadData也就理清楚了。下面回到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;
}
這里就是調(diào)用前面創(chuàng)建的三個StringLoader嫌褪,而后調(diào)用其buildLoadData方法呀枢,獲取到相應(yīng)的LoadData對象,這里我們可以知道笼痛,最終的loadData這個列表如下:
[
{LoadData: [{GlideUrl, HttpUrlFetcher},{GlideUrl, HttpUrlFetcher}]},
{LoadData:[{ObjectKey, AssetFileDescriptorLocalUriFetcher}]}]
至此硫狞,再看getCacheKeys的實現(xiàn)也就非常簡單了。
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;
}
因此此時的cacheKeys中的內(nèi)容就是:
[GlideUrl,ObjectKey]
這里我們分析了DecodeHelper類中晃痴,最復(fù)雜的獲取loadData的方法残吩,沒有在注冊這塊花太大的精力,后面的分析中倘核,我們會看到這個輔助類的使用泣侮。