Glide源码解析之DecodeHelper

前言

由名字可以看出这是一个解码的帮助类,里面缓存了LoadData和Key,以及很多从DecoderJob传递过来的参数。它的主要作用是提供解码所需要的的数据,并不进行实际的解码操作。

final class DecodeHelper<Transcode> {
    private final List<LoadData<?>> loadData = new ArrayList<>();
    private final List<Key> cacheKeys = new ArrayList<>();
    private Map<Class<?>, Transformation<?>> transformations;   //在BaseRequestOptions中为CachedHashCodeArrayMap
    private Object model;                       //String
    private Class<?> resourceClass;             //Object.class
    private Class<Transcode> transcodeClass;    //Drawable.class
}

getCacheKeys()

在这里获取缓存到的key,如果没有则会先获取LoadData,再获取LoadData里面的key。在Glide源码解析之RequestBuilder我们在load()传入的为String类型的 url,所以我们的model为String,则最终cacheKeys会包含GlideUrl(实现了Key接口),在下面会进行分析。

    List<Key> getCacheKeys() {
        if (!isCacheKeysSet) {
            isCacheKeysSet = true;
            cacheKeys.clear();
            List<LoadData<?>> loadData = getLoadData();
            
            //将LoadData里面的key都缓存起来
            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;
    }

getLoadData()

LoadData是一个封装了Key、List<key>、DataFetcher<Data>的类,里面没有任何操作。首先会获取已注册的加载器中所有可以加载当前模型的ModelLoader,再由它调用buildLoadData()生成LoadData。这里最终获取到的modelLoaders会包含HttpGlideUrlLoader,它最终会build一个Key为GlideUrl和DataFetcher为HttpUrlFetcher的LoadData出来。

    class LoadData<Data> {
        public final Key sourceKey;
        public final List<Key> alternateKeys;   //默认会赋值为Collections.<Key>emptyList()
        public final DataFetcher<Data> fetcher;
    }
    
    List<LoadData<?>> getLoadData() {
        if (!isLoadDataSet) {
            isLoadDataSet = true;
            loadData.clear();
            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;
    }
getModelLoaders()

获取能处理当前类型的ModelLoaders,而ModelLoader实际是由MultiModelLoaderFactory去build出来的。在MultiModelLoaderFactory中,将ModelLoaderFactory、modelClass(要加载的model,这里是String.class)、dataClass(加载的数据类型,例如InputStream.class)包装成一个Entry,就像上面的LoadData那样。而Entry的来源则是在Glide初始化的时候,由Registry设置给ModelLoaderRegistry,再设置给MultiModelLoaderFactory。

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

    //ModelLoaderRegistry
    public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
        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)) {    //是否能处理model类型
                if (isEmpty) {
                    filteredLoaders = new ArrayList<>(size - i);
                    isEmpty = false;
                }
                filteredLoaders.add(loader);
            }
        }
        return filteredLoaders;
    }
    
    //首先从缓存获取,获取不到再build一个新的,并存入缓存
    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;
    }
    
public class MultiModelLoaderFactory {

    private final List<Entry<?, ?>> entries = new ArrayList<>();
    
    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) {
            return this.modelClass.isAssignableFrom(modelClass);    //this.modelClass是否是modelClass的父类或者接口
        }
    }
    
    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)) {
                    //由于modelClass是String.class,所以最终只有modelClass为String.class的Entry才能执行到这里。
                    //比如有Entry(String.class, InputStream.class, new StringLoader.StreamFactory())
                    //所以loaders会add一个由StreamFactory去build出来的StringLoader。
                    alreadyUsedEntries.add(entry);
                    loaders.add(this.<Model, Object>build(entry));
                    alreadyUsedEntries.remove(entry);
                }
            }
            return loaders;
        } catch (Throwable t) {
            alreadyUsedEntries.clear();
            throw t;
        }
    }
    
    private <Model, Data> ModelLoader<Model, Data> build(@NonNull Entry<?, ?> entry) {
        return (ModelLoader<Model, Data>) Preconditions.checkNotNull(entry.factory.build(this));
    }
    
    //Entry的来源
    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);
    }
    
    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
    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
    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
    Glide(){
        registry
        .append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
        .append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
        .append(String.class, InputStream.class, new StringLoader.StreamFactory())
        .append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
        .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
    }

上面说到会由StreamFactory去build一个StringLoader,而StringLoader的构造函数又传入了一个由MultiModelLoaderFactory去build出来的ModelLoader。由于传给它的是Uri.class和InputStream.class,我们去Glide的构造函数找到对应的factory为HttpUriLoader的内部类Factory。它build了一个HttpUriLoader,但同时它的构造函数又传入一个新的ModelLoader,根据类型不难找到实际为HttpGlideUrlLoader。

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

    }

    //MultiModelLoaderFactory
    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) {
                if (alreadyUsedEntries.contains(entry)) {
                    ignoredAnyEntries = true;
                    continue;
                }
                if (entry.handles(modelClass, dataClass)) {
                    //匹配Uri.class和InputStream.class的Entry(Uri.class, InputStream.class, new HttpUriLoader.Factory())
                    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 {
                if (ignoredAnyEntries) {
                    return emptyModelLoader();
                } else {
                    throw new NoModelLoaderAvailableException(modelClass, dataClass);
                }
            }
        } catch (Throwable t) {
            alreadyUsedEntries.clear();
            throw t;
        }
    }
    
    //HttpUriLoader
    public static class Factory implements ModelLoaderFactory<Uri, InputStream> {
    
        @NonNull
        @Override
        public ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {
            return new HttpUriLoader(multiFactory.build(GlideUrl.class, InputStream.class));
        }

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

    }
StringLoader

StringLoader实现了ModelLoader接口,里面主要是两个方法,handles()在上面ModelLoaderRegistry.getModelLoaders()进行了判断,这里主要看下看下buildLoadData()。

由上面分析可知StringLoader传入了HttpUriLoader,而HttpUriLoader又传入了HttpGlideUrlLoader,所以这里实际上是使用了代理模式,将实际生成LoadData的操作最终交给了HttpGlideUrlLoader。所以最终生成的LoadData的sourceKey为GlideUrl,fetcher为HttpUrlFetcher。

public class StringLoader<Data> implements ModelLoader<String, Data> {
    private final ModelLoader<Uri, Data> uriLoader;

    public StringLoader(ModelLoader<Uri, Data> uriLoader) {
        this.uriLoader = uriLoader;
    }

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

    //是否能处理String类型的model
    @Override
    public boolean handles(@NonNull String model) {
        return true;
    }

}

    //HttpUriLoader
    public LoadData<InputStream> buildLoadData(@NonNull Uri model, int width, int height,
      @NonNull Options options) {
        //urlLoader为HttpGlideUrlLoader
        return urlLoader.buildLoadData(new GlideUrl(model.toString()), width, height, options);
    }
  
    //HttpGlideUrlLoader
    public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
                                               @NonNull Options options) {
        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));
    }

getRegisteredResourceClasses()

上面说过model.getClass()为String.class,在RequestBuilder的父类BaseRequestOptions中resourceClass默认为Object.class,在Glide源码解析之RequestBuilder我们在load()传入的为String Url,里面会调用asDrawable(),所以这里transcodeClass为Drawable.class。

首先会先从缓存中获取,如果没有则调用modelLoaderRegistry.getDataClasses(modelClass)获取String.class对应的dataClass,然后遍历它,再调用decoderRegistry.getResourceClasses(dataClass, resourceClass)获取对应已注册的resourceClass,最后也遍历registeredResourceClasses,根据registeredResourceClass,和transcodeClass获取最终能处理的registeredResourceClass。所以最后的List会包含Drawable.class。

    List<Class<?>> getRegisteredResourceClasses() {
        return glideContext.getRegistry()
                .getRegisteredResourceClasses(model.getClass(), resourceClass, transcodeClass);
    }
    
    //Registry
    public <Model, TResource, Transcode> List<Class<?>> getRegisteredResourceClasses(
            @NonNull Class<Model> modelClass /*String*/,
            @NonNull Class<TResource> resourceClass /*Object*/,
            @NonNull Class<Transcode> transcodeClass /*Drawable*/) {
        List<Class<?>> result =
                modelToResourceClassCache.get(modelClass, resourceClass, transcodeClass);

        if (result == null) {
            result = new ArrayList<>();
            List<Class<?>> dataClasses = modelLoaderRegistry.getDataClasses(modelClass);    //InputStream.class、ParcelFileDescriptor.class和AssetFileDescriptor.class
            for (Class<?> dataClass : dataClasses) {
                List<? extends Class<?>> registeredResourceClasses =
                        decoderRegistry.getResourceClasses(dataClass, resourceClass);       //GifDrawable.class、Bitmap.class、BitmapDrawable.class
                for (Class<?> registeredResourceClass : registeredResourceClasses) {
                    List<Class<Transcode>> registeredTranscodeClasses = transcoderRegistry
                            .getTranscodeClasses(registeredResourceClass, transcodeClass);  //Drawable.class
                    if (!registeredTranscodeClasses.isEmpty() && !result.contains(registeredResourceClass)) {
                        result.add(registeredResourceClass);                                //Drawable.class
                    }
                }
            }
            modelToResourceClassCache.put(
                    modelClass, resourceClass, transcodeClass, Collections.unmodifiableList(result));
        }

        return result;
    }
getDataClasses()

还是和上面获取ModelLoader一样,这里也是根据Entry中是否能handles()对应的modelClass来获取dataClasses。

由于modelClass为String.class,所以最终返回的List会包含InputStream.class、ParcelFileDescriptor.class和AssetFileDescriptor.class。

    //ModelLoaderRegistry
    public synchronized List<Class<?>> getDataClasses(@NonNull Class<?> modelClass) {
        return multiModelLoaderFactory.getDataClasses(modelClass);
    }
    
    //MultiModelLoaderFactory
    synchronized List<Class<?>> getDataClasses(@NonNull Class<?> modelClass) {
        List<Class<?>> result = new ArrayList<>();
        for (Entry<?, ?> entry : entries) {
            //上面说了Entry实际会在Glide的构造函数通过Registry的append()赋值,那么只要找出哪些modelClass为String.class对应的dataClass就行了。
            if (!result.contains(entry.dataClass) && entry.handles(modelClass)) {
                result.add(entry.dataClass);
            }
        }
        return result;
    }
    
    Glide(){
        registry
        .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())
    }
getResourceClasses()

第一个参数为InputStream.class,第二个参数为Drawable.class。由于decoders保存了所有在Glide构造函数中注册的bucket,所以在Glide的构造函数中找出对应dataClass为InputStream的resource即可。最终这里返回的List会包含GifDrawable.class、Bitmap.class、BitmapDrawable.class。

    //ResouceDecoderRegistry
    public synchronized <T, R> List<Class<R>> getResourceClasses(@NonNull Class<T> dataClass,
                                                                 @NonNull Class<R> resourceClass) {
        List<Class<R>> result = new ArrayList<>();
        for (String bucket : bucketPriorityList) {
            List<Entry<?, ?>> entries = decoders.get(bucket);
            if (entries == null) {
                continue;
            }
            for (Entry<?, ?> entry : entries) {
                if (entry.handles(dataClass, resourceClass)
                        && !result.contains(entry.resourceClass)) {
                    result.add((Class<R>) entry.resourceClass);
                }
            }
        }
        return result;
    }
ResourceDecoderRegistry

资源解码注册表,和MultiModelLoaderFactory作用类似,它们里面都有一个Entry保存了几个变量,并且都有handles()用来判断这个Entry能否处理对应的类型。

ResourceDecoderRegistry里面有一个bucketPriorityList,它是在Registry在的构造函数里赋值的。同时还用Map来保存了Entry,它则是在Glide的构造函数里通过Registry赋值的。

public class ResourceDecoderRegistry {
    private final List<String> bucketPriorityList = new ArrayList<>();
    private final Map<String, List<Entry<?, ?>>> decoders = new HashMap<>();

    public synchronized void setBucketPriorityList(@NonNull List<String> buckets) {
        List<String> previousBuckets = new ArrayList<>(bucketPriorityList);
        bucketPriorityList.clear();
        bucketPriorityList.addAll(buckets);
        
        //如果之前bucketPriorityList有的元素是现在没有,则同样保存下来
        for (String previousBucket : previousBuckets) {
            if (!buckets.contains(previousBucket)) {
                bucketPriorityList.add(previousBucket);
            }
        }
    }
    
    private static class Entry<T, R> {
        private final Class<T> dataClass;
        @Synthetic
        final Class<R> resourceClass;
        @Synthetic
        final ResourceDecoder<T, R> decoder;

        public Entry(@NonNull Class<T> dataClass, @NonNull Class<R> resourceClass,
                     ResourceDecoder<T, R> decoder) {
            this.dataClass = dataClass;
            this.resourceClass = resourceClass;
            this.decoder = decoder;
        }

        //由于resourceClass默认为Object.class,所以第二个判断为true,只需要判断dataClass就行了
        public boolean handles(@NonNull Class<?> dataClass, @NonNull Class<?> resourceClass) {
            return this.dataClass.isAssignableFrom(dataClass) && resourceClass
                    .isAssignableFrom(this.resourceClass);
        }
    }
    
}
    
public class Registry {
    
    public static final String BUCKET_GIF = "Gif";
    public static final String BUCKET_BITMAP = "Bitmap";
    public static final String BUCKET_BITMAP_DRAWABLE = "BitmapDrawable";
    private static final String BUCKET_PREPEND_ALL = "legacy_prepend_all";
    private static final String BUCKET_APPEND_ALL = "legacy_append";
    
    public Registry() {
        setResourceDecoderBucketPriorityList(
                Arrays.asList(BUCKET_GIF, BUCKET_BITMAP, BUCKET_BITMAP_DRAWABLE));
    }
    
    //所以ResourceDecoderRegistry的bucketPriorityList的值为[BUCKET_PREPEND_ALL,BUCKET_GIF,BUCKET_BITMAP,BUCKET_BITMAP_DRAWABLE,BUCKET_APPEND_ALL]
    public final Registry setResourceDecoderBucketPriorityList(@NonNull List<String> buckets) {
        List<String> modifiedBuckets = new ArrayList<>(buckets.size());
        modifiedBuckets.addAll(buckets);
        modifiedBuckets.add(0, BUCKET_PREPEND_ALL);
        modifiedBuckets.add(BUCKET_APPEND_ALL);
        decoderRegistry.setBucketPriorityList(modifiedBuckets);
        return this;
    }
    
}

decoders以bucket为key,List<Entry<?, ?>>为value,在Glide的构造函数中通过Registry赋值。

    //ResouceDecoderRegistry
    private synchronized List<Entry<?, ?>> getOrAddEntryList(@NonNull String bucket) {
        if (!bucketPriorityList.contains(bucket)) {
            bucketPriorityList.add(bucket);
        }
        List<Entry<?, ?>> entries = decoders.get(bucket);
        if (entries == null) {
            entries = new ArrayList<>();
            decoders.put(bucket, entries);
        }
        return entries;
    }
    
    public synchronized <T, R> void append(@NonNull String bucket,
                                           @NonNull ResourceDecoder<T, R> decoder,
                                           @NonNull Class<T> dataClass, @NonNull Class<R> resourceClass) {
        //将Entry添加到key为bucket的List里
        getOrAddEntryList(bucket).add(new Entry<>(dataClass, resourceClass, decoder));
    }
    
    //Registry
    public <Data, TResource> Registry append(
            @NonNull String bucket,
            @NonNull Class<Data> dataClass,
            @NonNull Class<TResource> resourceClass,
            @NonNull ResourceDecoder<Data, TResource> decoder) {
        decoderRegistry.append(bucket, decoder, dataClass, resourceClass);
        return this;
    }
    
    Glide(){
        registry
                /* Bitmaps */
                .append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder)
                /* BitmapDrawables */
                .append(
                        Registry.BUCKET_BITMAP_DRAWABLE,
                        InputStream.class,
                        BitmapDrawable.class,
                        new BitmapDrawableDecoder<>(resources, streamBitmapDecoder))
                /* GIFs */
                .append(
                        Registry.BUCKET_GIF,
                        InputStream.class,
                        GifDrawable.class,
                        new StreamGifDecoder(imageHeaderParsers, byteBufferGifDecoder, arrayPool))
    }
getTranscodeClasses()

熟悉的名字,熟悉的味道,这个类比上面那两个简单,自己按照规则看下就懂了。

public class TranscoderRegistry {
    private final List<Entry<?, ?>> transcoders = new ArrayList<>();

    public synchronized <Z, R> void register(
      @NonNull Class<Z> decodedClass, @NonNull Class<R> transcodedClass,
      @NonNull ResourceTranscoder<Z, R> transcoder) {
        transcoders.add(new Entry<>(decodedClass, transcodedClass, transcoder));
    }
  
    public synchronized <Z, R> List<Class<R>> getTranscodeClasses(
      @NonNull Class<Z> resourceClass, @NonNull Class<R> transcodeClass) {
        List<Class<R>> transcodeClasses = new ArrayList<>();

        //如果transcodeClass是resourceClass的父类(比如Drawable是BitmapDrawable和GifDrawable的父类)则为true。
        //所以如果resourceClass传入的是Drawable的子类,则最终只会添加Drawable.class
        if (transcodeClass.isAssignableFrom(resourceClass)) {
          transcodeClasses.add(transcodeClass);
          return transcodeClasses;
        }

        for (Entry<?, ?> entry : transcoders) {
            if (entry.handles(resourceClass, transcodeClass)) {
                //这里有效的是当传入Bitmap.class和Drawable.class的时候,所以最后会添加Drawable.calss
                transcodeClasses.add(transcodeClass);
            }
        }

        return transcodeClasses;
    }
    
    private static final class Entry<Z, R> {
        private final Class<Z> fromClass;
        private final Class<R> toClass;
        @Synthetic
        final ResourceTranscoder<Z, R> transcoder;

        Entry(@NonNull Class<Z> fromClass, @NonNull Class<R> toClass,
              @NonNull ResourceTranscoder<Z, R> transcoder) {
            this.fromClass = fromClass;
            this.toClass = toClass;
            this.transcoder = transcoder;
        }

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

}

    //Registry
    public <TResource, Transcode> Registry register(
            @NonNull Class<TResource> resourceClass, @NonNull Class<Transcode> transcodeClass,
            @NonNull ResourceTranscoder<TResource, Transcode> transcoder) {
        transcoderRegistry.register(resourceClass, transcodeClass, transcoder);
        return this;
    }
    
    //Glide
    Glide(){
        registry
                /* Transcoders */
                .register(
                        Bitmap.class,
                        BitmapDrawable.class,
                        new BitmapDrawableTranscoder(resources))
    }

getTransformation()

Transformation是一个接口,继承了Key接口,同时自己有一个transform方法,用来将Resource转换为另一个Resource。比如它的实现类CenterCrop,就是将Bitmap转为centerCrop样子的Bitmap。

getTransformation()则根据之前在transformations存好的键值对来获取Transformation。

    <Z> Transformation<Z> getTransformation(Class<Z> resourceClass) {
        Transformation<Z> result = (Transformation<Z>) transformations.get(resourceClass);     //由BaseRequestOptions的transformations传递进来
        if (result == null) {
            for (Entry<Class<?>, Transformation<?>> entry : transformations.entrySet()) {
                if (entry.getKey().isAssignableFrom(resourceClass)) {
                    result = (Transformation<Z>) entry.getValue();
                    break;
                }
            }
        }

        if (result == null) {
            if (transformations.isEmpty() && isTransformationRequired) {
                throw new IllegalArgumentException(
                        "Missing transformation for " + resourceClass + ". If you wish to"
                                + " ignore unknown resource types, use the optional transformation methods.");
            } else {
                return UnitTransformation.get();    //这个默认返回原Resource,不做转换
            }
        }
        return result;
    }

在我们使用RequestBuilder显式调用centerCrop()或者其他转换时,最终会将对应的类型和Transformation存进transformations。如果没有显式调用,但是ImageView本身设置了转换的(比如设置了android:scaleType="centerCrop"),会在into()时进行设置存进transformations。

    Glide.with(this)
            .load("")
            .centerCrop()
            .into(imageView);
        
    //BaseRequestOptions    
    public T centerCrop() {
        return transform(DownsampleStrategy.CENTER_OUTSIDE, new CenterCrop());
    }   
    
    final T transform(@NonNull DownsampleStrategy downsampleStrategy,
                      @NonNull Transformation<Bitmap> transformation) {
        if (isAutoCloneEnabled) {
            //在clone()中会设置isAutoCloneEnabled为false,所以最终还是会走到下面的语句
            return clone().transform(downsampleStrategy, transformation);
        }

        downsample(downsampleStrategy);
        return transform(transformation);
    }
    
    public T transform(@NonNull Transformation<Bitmap> transformation) {
        return transform(transformation, /*isRequired=*/ true);
    }
    
    T transform(
            @NonNull Transformation<Bitmap> transformation, boolean isRequired) {
        if (isAutoCloneEnabled) {
            return clone().transform(transformation, isRequired);
        }

        DrawableTransformation drawableTransformation =
                new DrawableTransformation(transformation, isRequired);
                
        //最终transformations添加的键值对为下面这些
        transform(Bitmap.class, transformation, isRequired);
        transform(Drawable.class, drawableTransformation, isRequired);
        transform(BitmapDrawable.class, drawableTransformation.asBitmapDrawable(), isRequired);
        transform(GifDrawable.class, new GifDrawableTransformation(transformation), isRequired);
        return selfOrThrowIfLocked();
    }
    
    <Y> T transform(
            @NonNull Class<Y> resourceClass,
            @NonNull Transformation<Y> transformation,
            boolean isRequired) {
        if (isAutoCloneEnabled) {
            return clone().transform(resourceClass, transformation, isRequired);
        }

        transformations.put(resourceClass, transformation); //在这里添加进去
        fields |= TRANSFORMATION;
        isTransformationAllowed = true;
        fields |= TRANSFORMATION_ALLOWED;
        // Always set to false here. Known scale only transformations will call this method and then
        // set isScaleOnlyOrNoTransform to true immediately after.
        isScaleOnlyOrNoTransform = false;
        if (isRequired) {
            fields |= TRANSFORMATION_REQUIRED;
            isTransformationRequired = true;
        }
        return selfOrThrowIfLocked();
    }

hasLoadPath()

LoadPath主要是封装了List<DecodePath<Data, ResourceType, Transcode>>,从而利用DecodePath根据给定的数据类型解码和转码资源类型。

在getLoadPath中首先从缓存中获取,如果没获取到则会继续获取decodePaths,如果decodePaths不为空,则创建一个新的LoadPath并传入缓存,最后返回。

    //DecodeHelper
    boolean hasLoadPath(Class<?> dataClass) {
        return getLoadPath(dataClass) != null;
    }
    
    //Registry
    <Data> LoadPath<Data, ?, Transcode> getLoadPath(Class<Data> dataClass) {
        return glideContext.getRegistry().getLoadPath(dataClass, resourceClass, transcodeClass);
    }
    
    public <Data, TResource, Transcode> LoadPath<Data, TResource, Transcode> getLoadPath(
            @NonNull Class<Data> dataClass, @NonNull Class<TResource> resourceClass,
            @NonNull Class<Transcode> transcodeClass) {
        LoadPath<Data, TResource, Transcode> result =
                loadPathCache.get(dataClass, resourceClass, transcodeClass);
        if (loadPathCache.isEmptyLoadPath(result)) {
            //返回的是一个特定的LoadPath,代表之前没有发现可用的LoadPath。
            //当下面的decodePaths.isEmpty()时,loadPathCache存入的result为null,这时实际存入的是一个特定的NO_PATHS_SIGNAL。
            return null;
        } else if (result == null) {
            List<DecodePath<Data, TResource, Transcode>> decodePaths =
                    getDecodePaths(dataClass, resourceClass, transcodeClass);
                    
            if (decodePaths.isEmpty()) {
                //从给定的数据类中可能无法解码或转码为所需的类型。
                result = null;
            } else {
                result = new LoadPath<>(
                                dataClass, resourceClass, transcodeClass, decodePaths, throwableListPool);
            }
            loadPathCache.put(dataClass, resourceClass, transcodeClass, result);
        }
        return result;
    }
    
    //DecodePath则主是封装List<? extends ResourceDecoder<DataType, ResourceType>>和ResourceTranscoder<ResourceType, Transcode> transcoder来进行解码和转码工作
    private <Data, TResource, Transcode> List<DecodePath<Data, TResource, Transcode>> getDecodePaths(
            @NonNull Class<Data> dataClass/*InputStream.class*/, @NonNull Class<TResource> resourceClass/*Object.class*/,
            @NonNull Class<Transcode> transcodeClass/*Drawable.class*/) {
        List<DecodePath<Data, TResource, Transcode>> decodePaths = new ArrayList<>();
        
        //这些getXXXClasses获取上面都有说过
        List<Class<TResource>> registeredResourceClasses =
                decoderRegistry.getResourceClasses(dataClass, resourceClass);       //GifDrawable.class、Bitmap.class、BitmapDrawable.class

        for (Class<TResource> registeredResourceClass : registeredResourceClasses) {
            List<Class<Transcode>> registeredTranscodeClasses =
                    transcoderRegistry.getTranscodeClasses(registeredResourceClass, transcodeClass);    //Drawable.class

            for (Class<Transcode> registeredTranscodeClass : registeredTranscodeClasses) {

                List<ResourceDecoder<Data, TResource>> decoders =
                        decoderRegistry.getDecoders(dataClass, registeredResourceClass);                //StreamGifDecoder、BitmapDrawableDecoder
                ResourceTranscoder<TResource, Transcode> transcoder =
                        transcoderRegistry.get(registeredResourceClass, registeredTranscodeClass);      //BitmapDrawableTranscoder
                @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
                DecodePath<Data, TResource, Transcode> path =
                        new DecodePath<>(dataClass/*InputStream.class*/, registeredResourceClass/*Bitmap.class*/, registeredTranscodeClass/*Drawable.class*/,
                                decoders/*StreamGifDecoder、BitmapDrawableDecoder*/, transcoder/*BitmapDrawableTranscoder*/, throwableListPool);
                decodePaths.add(path);
            }
        }
        return decodePaths;
    }

getDiskCache()

获取磁盘缓存,具体请看Glide源码解析之DiskCache

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