Glide 源码分析之二 load

作者: sunrain_ | 来源:发表于2017-05-17 21:10 被阅读99次

    前言

    在上篇中分析完了 with() 方法,Glide 分析之一 with.
    本篇中,我们将通过 with() 方法返回的 RequestManager,来分析 load(resourceId) 的执行过程。

    load

    load() 方法在 RequestManager 中有8种重载,结合本篇的问题,这里只分析 load(resourceId) 方法。

    public DrawableTypeRequest<Integer> load(Integer resourceId) {
        return (DrawableTypeRequest<Integer>) fromResource().load(resourceId);(锚点1)
    }
    

    load(Integer resourceId) 方法内先调用了 fromResource() 方法:
    ```java`
    public DrawableTypeRequest<Integer> fromResource() {
    return (DrawableTypeRequest<Integer>) loadGeneric(Integer.class)(锚点2)
    .signature(ApplicationVersionSignature.obtain(context));
    }

    看 loadGeneric(Integer.class) 方法:
    ```java
    private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
        ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
        ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader = Glide.buildFileDescriptorModelLoader(modelClass, context);
        if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
            throw new IllegalArgumentException("省略");
        }
    
        return optionsApplier.apply(new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context, 
               glide, requestTracker, lifecycle, optionsApplier));
    }
    

    方法内部通过 Glide.buildStreamModelLoader() 和 Glide.buildFileDescriptorModelLoader() 方法创建两个 ModelLoader 对象用于图片加载。
    这两个方法会根据传入参数,返回相应的 ModelLoader 实现类。本例中,buildStreamModelLoader() 返回 StreamResourceLoader,buildFileDescriptorModelLoader() 返回 FileDescriptorResourceLoader,这两个方法在最后有详细分析。

    loadGeneric() 方法最后创建了 DrawableTypeRequest 对象,并返回。

    锚点2处执行完之后继续调用 signature() 方法,标记了一个 Key,然后把 DrawableTypeRequest<Integer> 对象返回出去。

    上一层拿到 DrawableTypeRequest<Integer> 对象后调用了它的 load(resourceId) 方法(见:锚点1):

    public DrawableRequestBuilder<ModelType> load(ModelType model) {
        super.load(model);
        return this;
    }
    
    public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
        this.model = model;
        isModelSet = true;
        return this;
    }
    

    这里保存了 ModelType,在本例中就是 Integer.class.
    最终 Glide.load() 方法返回 DrawableTypeRequest<Integer> 对象。

    至此,load() 方法主线流程就分析完毕了,接下来会继续分析 Glide.buildStreamModelLoader() 方法是如何返回 ModelLoader 的。

    Glide.buildStreamModelLoader()

    public static <T> ModelLoader<T, InputStream> buildStreamModelLoader(Class<T> modelClass, Context context) {
        return buildModelLoader(modelClass, InputStream.class, context);(锚点3)
    }
    
    public static <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass, Context context) {
        if (modelClass == null) {
            ···
            return null;
        }
        return Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass);(锚点4)
    }
    
    public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass) {
        ···
        final ModelLoaderFactory<T, Y> factory = getFactory(modelClass, resourceClass);
        if (factory != null) {
            result = factory.build(context, this);
            ···
        } else {
            ···
        }
        return result;
    }
    
    private <T, Y> ModelLoaderFactory<T, Y> getFactory(Class<T> modelClass, Class<Y> resourceClass) {
        Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> resourceToFactories = modelClassToResourceFactories.get(modelClass);
        ModelLoaderFactory/*T, Y*/ result = null;
        if (resourceToFactories != null) {
            result = resourceToFactories.get(resourceClass);
        }
    
        if (result == null) {
            for (Class<? super T> registeredModelClass : modelClassToResourceFactories.keySet()) {
                if (registeredModelClass.isAssignableFrom(modelClass)) {
                    Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> currentResourceToFactories =
                            modelClassToResourceFactories.get(registeredModelClass);
                    if (currentResourceToFactories != null) {
                        result = currentResourceToFactories.get(resourceClass);
                        if (result != null) {
                            break;
                        }
                    }
                }
            }
        }
    
        return result;
    }
    

    可以看到在 getFactory() 方法中根据传入的 modelClass 从 modelClassToResourceFactories 中获取了 value
    为 ModelLoaderFactory 的 Map,又根据传入的 resourceClass 从 Map 中取出 ModelLoaderFactory 对象。

    那么 modelClassToResourceFactories 的数据是在哪里放入的?
    在 buildModelLoader() 方法中调用了 Glide.get() 方法(见:锚点4):

    public static Glide get(Context context) {
        if (glide == null) {
            synchronized (Glide.class) {
                if (glide == null) {
                   ···
                    glide = builder.createGlide();
                   ···
                }
            }
        }
        return glide;
    }
    
    Glide createGlide() {
        ···
        return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
    }
    
    Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
        ···
        register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory());
        register(File.class, InputStream.class, new StreamFileLoader.Factory());
        register(int.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
        register(int.class, InputStream.class, new StreamResourceLoader.Factory());
        register(Integer.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
        register(Integer.class, InputStream.class, new StreamResourceLoader.Factory());
        register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory());
        register(String.class, InputStream.class, new StreamStringLoader.Factory());
        register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory());
        register(Uri.class, InputStream.class, new StreamUriLoader.Factory());
        register(URL.class, InputStream.class, new StreamUrlLoader.Factory());
        register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
        register(byte[].class, InputStream.class, new StreamByteArrayLoader.Factory());
        ···
    }
    
    public <T, Y> void register(Class<T> modelClass, Class<Y> resourceClass, ModelLoaderFactory<T, Y> factory) {
        ModelLoaderFactory<T, Y> removed = loaderFactory.register(modelClass, resourceClass, factory);
        ···
    }
    
    public synchronized <T, Y> ModelLoaderFactory<T, Y> register(Class<T> modelClass, Class<Y> resourceClass,
                                                                 ModelLoaderFactory<T, Y> factory) {
        ···
        Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> resourceToFactories = modelClassToResourceFactories.get(modelClass);
        if (resourceToFactories == null) {
            resourceToFactories = new HashMap<Class/*Y*/, ModelLoaderFactory/*T, Y*/>();
            modelClassToResourceFactories.put(modelClass, resourceToFactories);
        }
        ···
        return previous;
    }
    
    

    从锚点2、锚点3可以知道 modelClass 为 Integer.class,resourceClass 为 InputStream.class,在 Glide 的构造函数找到对应注册的 ModelLoaderFactory 为 StreamResourceLoader.Factory,所以 buildStreamModelLoader() 方法返回的是 StreamResourceLoader 对象。
    同理 buildFileDescriptorModelLoader() 方法返回 FileDescriptorResourceLoader 对象。

    至此,根据 ModelType,创建 DrawableRequestBuilder 和其中的 ModelLoader,为下一步加载图片做好准备的流程就分析完毕了。

    在下一篇中,我们会继续分析 into() 方法:Glide 源码分析之三 into.

    谢谢大家。

    参考链接

    Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程

    相关文章

      网友评论

        本文标题:Glide 源码分析之二 load

        本文链接:https://www.haomeiwen.com/subject/soxdxxtx.html