美文网首页
Android图片加载框架解析(二):从源码的角度理解Glide

Android图片加载框架解析(二):从源码的角度理解Glide

作者: Bfmall | 来源:发表于2021-04-21 22:34 被阅读0次

    <meta charset="utf-8">

    在多数情况下,我们想要在界面上加载并展示一张图片只需要一行代码就能实现,如下所示:

    Glide.with(this).load(url).into(imageView);
    复制代码
    
    

    虽说只有这简简单单的一行代码,但大家可能不知道的是,Glide 在背后帮我们默默执行了成吨的工作。这个形容词我想了很久,因为我觉得用非常多这个形容词不足以描述 Glide 背后的工作量,我查到的英文资料是用 tons of work 来进行形容的,因此我觉得这里使用成吨来形容更加贴切一些。

    虽说我们在平时使用 Glide 的时候格外地简单和方便,但是知其然也要知其所以然。那么今天我们就来解析一下 Glide 的源码,看看它在这些简单用法的背后,到底执行了多么复杂的工作。

    如何阅读源码

    在开始解析 Glide 源码之前,我想先和大家谈一下该如何阅读源码,这个问题也是我平时被问得比较多的,因为很多人都觉得阅读源码是一件比较困难的事情。

    那么阅读源码到底困难吗?这个当然主要还是要视具体的源码而定。比如同样是图片加载框架,我读 Volley 的源码时就感觉酣畅淋漓,并且对 Volley 的架构设计和代码质量深感佩服。读 Glide 的源码时却让我相当痛苦,代码极其难懂。当然这里我并不是说 Glide 的代码写得不好,只是因为 Glide 和复杂程度和 Volley 完全不是在一个量级上的。

    那么,虽然源码的复杂程度是外在的不可变条件,但我们却可以通过一些技巧来提升自己阅读源码的能力。这里我和大家分享一下我平时阅读源码时所使用的技巧,简单概括就是八个字:抽丝剥茧、点到即止。应该认准一个功能点,然后去分析这个功能点是如何实现的。但只要去追寻主体的实现逻辑即可,千万不要试图去搞懂每一行代码都是什么意思,那样很容易会陷入到思维黑洞当中,而且越陷越深。因为这些庞大的系统都不是由一个人写出来的,每一行代码都想搞明白,就会感觉自己是在盲人摸象,永远也研究不透。如果只是去分析主体的实现逻辑,那么就有比较明确的目的性,这样阅读源码会更加轻松,也更加有成效。

    而今天带大家阅读的 Glide 源码就非常适合使用这个技巧,因为 Glide 的源码太复杂了,千万不要试图去搞明白它每行代码的作用,而是应该只分析它的主体实现逻辑。那么我们本篇文章就先确立好一个目标,就是要通过阅读源码搞明白下面这行代码:

    Glide.with(this).load(url).into(imageView);
    复制代码
    
    

    到底是如何实现将一张网络图片展示到 ImageView 上面的。先将 Glide 的一整套图片加载机制的基本流程梳理清楚,然后我们再通过后面的几篇文章具体去了解 Glide 源码方方面面的细节。

    准备好了吗?那么我们现在开始。

    源码下载

    既然是要阅读 Glide 的源码,那么我们自然需要先将 Glide 的源码下载下来。其实如果你是使用在 build.gradle 中添加依赖的方式将 Glide 引入到项目中的,那么源码自动就已经下载下来了,在 Android Studio 中就可以直接进行查看。

    不过,使用添加依赖的方式引入的 Glide,我们只能看到它的源码,但不能做任何的修改,如果你还需要修改它的源码的话,可以到 GitHub 上面将它的完整源码下载下来。

    Glide 的 GitHub 主页的地址是:github.com/bumptech/gl…

    不过在这个地址下载到的永远都是最新的源码,有可能还正在处于开发当中。而我们整个系列都是使用 Glide 3.7.0 这个版本来进行讲解的,因此如果你需要专门去下载 3.7.0 版本的源码,可以到这个地址进行下载:github.com/bumptech/gl…

    开始阅读

    我们在上一篇文章中已经学习过了,Glide 最基本的用法就是三步走:先 with(),再 load(),最后 into()。那么我们开始一步步阅读这三步走的源码,先从 with() 看起。

    1. with()

    with() 方法是 Glide 类中的一组静态方法,它有好几个方法重载,我们来看一下 Glide 类中所有 with() 方法的方法重载:

    public class Glide {
    
        ...
    
        public static RequestManager with(Context context) {
            RequestManagerRetriever retriever = RequestManagerRetriever.get();
            return retriever.get(context);
        }
    
        public static RequestManager with(Activity activity) {
            RequestManagerRetriever retriever = RequestManagerRetriever.get();
            return retriever.get(activity);
        }
    
        public static RequestManager with(FragmentActivity activity) {
            RequestManagerRetriever retriever = RequestManagerRetriever.get();
            return retriever.get(activity);
        }
    
        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        public static RequestManager with(android.app.Fragment fragment) {
            RequestManagerRetriever retriever = RequestManagerRetriever.get();
            return retriever.get(fragment);
        }
    
        public static RequestManager with(Fragment fragment) {
            RequestManagerRetriever retriever = RequestManagerRetriever.get();
            return retriever.get(fragment);
        }
    }
    复制代码
    
    

    可以看到,with() 方法的重载种类非常多,既可以传入 Activity,也可以传入 Fragment 或者是 Context。每一个 with() 方法重载的代码都非常简单,都是先调用 RequestManagerRetriever 的静态 get() 方法得到一个 RequestManagerRetriever 对象,这个静态 get() 方法就是一个单例实现,没什么需要解释的。然后再调用 RequestManagerRetriever 的实例 get() 方法,去获取 RequestManager 对象。

    而 RequestManagerRetriever 的实例 get() 方法中的逻辑是什么样的呢?我们一起来看一看:

    public class RequestManagerRetriever implements Handler.Callback {
    
        private static final RequestManagerRetriever INSTANCE = new RequestManagerRetriever();
    
        private volatile RequestManager applicationManager;
    
        ...
    
        /**
         * Retrieves and returns the RequestManagerRetriever singleton.
         */
        public static RequestManagerRetriever get() {
            return INSTANCE;
        }
    
        private RequestManager getApplicationManager(Context context) {
    
            if (applicationManager == null) {
                synchronized (this) {
                    if (applicationManager == null) {
    
                        applicationManager = new RequestManager(context.getApplicationContext(),
                                new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
                    }
                }
            }
            return applicationManager;
        }
    
        public RequestManager get(Context context) {
            if (context == null) {
                throw new IllegalArgumentException("You cannot start a load on a null Context");
            } else if (Util.isOnMainThread() && !(context instanceof Application)) {
                if (context instanceof FragmentActivity) {
                    return get((FragmentActivity) context);
                } else if (context instanceof Activity) {
                    return get((Activity) context);
                } else if (context instanceof ContextWrapper) {
                    return get(((ContextWrapper) context).getBaseContext());
                }
            }
            return getApplicationManager(context);
        }
    
        public RequestManager get(FragmentActivity activity) {
            if (Util.isOnBackgroundThread()) {
                return get(activity.getApplicationContext());
            } else {
                assertNotDestroyed(activity);
                FragmentManager fm = activity.getSupportFragmentManager();
                return supportFragmentGet(activity, fm);
            }
        }
    
        public RequestManager get(Fragment fragment) {
            if (fragment.getActivity() == null) {
                throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
            }
            if (Util.isOnBackgroundThread()) {
                return get(fragment.getActivity().getApplicationContext());
            } else {
                FragmentManager fm = fragment.getChildFragmentManager();
                return supportFragmentGet(fragment.getActivity(), fm);
            }
        }
    
        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        public RequestManager get(Activity activity) {
            if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
                return get(activity.getApplicationContext());
            } else {
                assertNotDestroyed(activity);
                android.app.FragmentManager fm = activity.getFragmentManager();
                return fragmentGet(activity, fm);
            }
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        private static void assertNotDestroyed(Activity activity) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
                throw new IllegalArgumentException("You cannot start a load for a destroyed activity");
            }
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        public RequestManager get(android.app.Fragment fragment) {
            if (fragment.getActivity() == null) {
                throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
            }
            if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
                return get(fragment.getActivity().getApplicationContext());
            } else {
                android.app.FragmentManager fm = fragment.getChildFragmentManager();
                return fragmentGet(fragment.getActivity(), fm);
            }
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
            RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
            if (current == null) {
                current = pendingRequestManagerFragments.get(fm);
                if (current == null) {
                    current = new RequestManagerFragment();
                    pendingRequestManagerFragments.put(fm, current);
                    fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                    handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
                }
            }
            return current;
        }
    
        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
            RequestManagerFragment current = getRequestManagerFragment(fm);
            RequestManager requestManager = current.getRequestManager();
            if (requestManager == null) {
                requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
                current.setRequestManager(requestManager);
            }
            return requestManager;
        }
    
        SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm) {
            SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
            if (current == null) {
                current = pendingSupportRequestManagerFragments.get(fm);
                if (current == null) {
                    current = new SupportRequestManagerFragment();
                    pendingSupportRequestManagerFragments.put(fm, current);
                    fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                    handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
                }
            }
            return current;
        }
    
        RequestManager supportFragmentGet(Context context, FragmentManager fm) {
            SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
            RequestManager requestManager = current.getRequestManager();
            if (requestManager == null) {
                requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
                current.setRequestManager(requestManager);
            }
            return requestManager;
        }
    
        ...
    }
    复制代码
    
    

    上述代码虽然看上去逻辑有点复杂,但是将它们梳理清楚后还是很简单的。RequestManagerRetriever 类中看似有很多个 get() 方法的重载,什么 Context 参数,Activity 参数,Fragment 参数等等,实际上只有两种情况而已,即传入 Application 类型的参数,和传入非 Application 类型的参数。

    我们先来看传入 Application 参数的情况。如果在 Glide.with() 方法中传入的是一个 Application 对象,那么这里就会调用带有 Context 参数的 get() 方法重载,然后会在第 44 行调用 getApplicationManager() 方法来获取一个 RequestManager 对象。其实这是最简单的一种情况,因为 Application 对象的生命周期即应用程序的生命周期,因此 Glide 并不需要做什么特殊的处理,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话,Glide 的加载也会同时终止。

    接下来我们看传入非 Application 参数的情况。不管你在 Glide.with() 方法中传入的是 Activity、FragmentActivity、v4 包下的 Fragment、还是 app 包下的 Fragment,最终的流程都是一样的,那就是会向当前的 Activity 当中添加一个隐藏的 Fragment。具体添加的逻辑是在上述代码的第 117 行和第 141 行,分别对应的 app 包和 v4 包下的两种 Fragment 的情况。那么这里为什么要添加一个隐藏的 Fragment 呢?因为 Glide 需要知道加载的生命周期。很简单的一个道理,如果你在某个 Activity 上正在加载着一张图片,结果图片还没加载出来,Activity 就被用户关掉了,那么图片还应该继续加载吗?当然不应该。可是 Glide 并没有办法知道 Activity 的生命周期,于是 Glide 就使用了添加隐藏 Fragment 的这种小技巧,因为 Fragment 的生命周期和 Activity 是同步的,如果 Activity 被销毁了,Fragment 是可以监听到的,这样 Glide 就可以捕获这个事件并停止图片加载了。

    这里额外再提一句,从第 48 行代码可以看出,如果我们是在非主线程当中使用的 Glide,那么不管你是传入的 Activity 还是 Fragment,都会被强制当成 Application 来处理。不过其实这就属于是在分析代码的细节了,本篇文章我们将会把目光主要放在 Glide 的主线工作流程上面,后面不会过多去分析这些细节方面的内容。

    总体来说,第一个 with() 方法的源码还是比较好理解的。其实就是为了得到一个 RequestManager 对象而已,然后 Glide 会根据我们传入 with() 方法的参数来确定图片加载的生命周期,并没有什么特别复杂的逻辑。不过复杂的逻辑还在后面等着我们呢,接下来我们开始分析第二步,load() 方法。

    1. load()

    由于 with() 方法返回的是一个 RequestManager 对象,那么很容易就能想到,load() 方法是在 RequestManager 类当中的,所以说我们首先要看的就是 RequestManager 这个类。不过在上一篇文章中我们学过,Glide 是支持图片 URL 字符串、图片本地路径等等加载形式的,因此 RequestManager 中也有很多个 load() 方法的重载。但是这里我们不可能把每个 load() 方法的重载都看一遍,因此我们就只选其中一个加载图片 URL 字符串的 load() 方法来进行研究吧。

    RequestManager 类的简化代码如下所示:

    
    public class RequestManager implements LifecycleListener {
    
        ...
    
        /**
         * Returns a request builder to load the given {@link String}.
         * signature.
         *
         * @see #fromString()
         * @see #load(Object)
         *
         * @param string A file path, or a uri or url handled by {@link com.bumptech.glide.load.model.UriLoader}.
         */
        public DrawableTypeRequest<String> load(String string) {
            return (DrawableTypeRequest<String>) fromString().load(string);
        }
    
        /**
         * Returns a request builder that loads data from {@link String}s using an empty signature.
         *
         * <p>
         *     Note - this method caches data using only the given String as the cache key. If the data is a Uri outside of
         *     your control, or you otherwise expect the data represented by the given String to change without the String
         *     identifier changing, Consider using
         *     {@link GenericRequestBuilder#signature(Key)} to mixin a signature
         *     you create that identifies the data currently at the given String that will invalidate the cache if that data
         *     changes. Alternatively, using {@link DiskCacheStrategy#NONE} and/or
         *     {@link DrawableRequestBuilder#skipMemoryCache(boolean)} may be appropriate.
         * </p>
         *
         * @see #from(Class)
         * @see #load(String)
         */
        public DrawableTypeRequest<String> fromString() {
            return loadGeneric(String.class);
        }
    
        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("Unknown type " + modelClass + ". You must provide a Model of a type for"
                        + " which there is a registered ModelLoader, if you are using a custom model, you must first call"
                        + " Glide#register with a ModelLoaderFactory for your custom model class");
            }
            return optionsApplier.apply(
                    new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
                            glide, requestTracker, lifecycle, optionsApplier));
        }
    
        ...
    
    }
    

    RequestManager 类的代码是非常多的,但是经过我这样简化之后,看上去就比较清爽了。在我们只探究加载图片 URL 字符串这一个 load() 方法的情况下,那么比较重要的方法就只剩下上述代码中的这三个方法。

    那么我们先来看 load() 方法,这个方法中的逻辑是非常简单的,只有一行代码,就是先调用了 fromString() 方法,再调用 load() 方法,然后把传入的图片 URL 地址传进去。而 fromString() 方法也极为简单,就是调用了 loadGeneric() 方法,并且指定参数为 String.class,因为 load() 方法传入的是一个字符串参数。那么看上去,好像主要的工作都是在 loadGeneric() 方法中进行的了。

    其实 loadGeneric() 方法也没几行代码,这里分别调用了 Glide.buildStreamModelLoader() 方法和 Glide.buildFileDescriptorModelLoader() 方法来获得 ModelLoader 对象。ModelLoader 对象是用于加载图片的,而我们给 load() 方法传入不同类型的参数,这里也会得到不同的 ModelLoader 对象。不过 buildStreamModelLoader() 方法内部的逻辑还是蛮复杂的,这里就不展开介绍了,要不然篇幅实在收不住,感兴趣的话你可以自己研究。由于我们刚才传入的参数是 String.class,因此最终得到的是 StreamStringLoader 对象,它是实现了 ModelLoader 接口的。

    最后我们可以看到,loadGeneric() 方法是要返回一个 DrawableTypeRequest 对象的,因此在 loadGeneric() 方法的最后又去 new 了一个 DrawableTypeRequest 对象,然后把刚才获得的 ModelLoader 对象,还有一大堆杂七杂八的东西都传了进去。具体每个参数的含义和作用就不解释了,我们只看主线流程。

    那么这个 DrawableTypeRequest 的作用是什么呢?我们来看下它的源码,如下所示:

    public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
        private final ModelLoader<ModelType, InputStream> streamModelLoader;
        private final ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader;
        private final RequestManager.OptionsApplier optionsApplier;
    
        private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
                ModelLoader<A, InputStream> streamModelLoader,
                ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
                Class<R> transcodedClass,
                ResourceTranscoder<Z, R> transcoder) {
            if (streamModelLoader == null && fileDescriptorModelLoader == null) {
                return null;
            }
    
            if (transcoder == null) {
                transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
            }
            DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
                    resourceClass);
            ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
                    fileDescriptorModelLoader);
            return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
        }
    
        DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
                ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
                RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
            super(context, modelClass,
                    buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
                            GlideDrawable.class, null),
                    glide, requestTracker, lifecycle);
            this.streamModelLoader = streamModelLoader;
            this.fileDescriptorModelLoader = fileDescriptorModelLoader;
            this.optionsApplier = optionsApplier;
        }
    
        /**
         * Attempts to always load the resource as a {@link android.graphics.Bitmap}, even if it could actually be animated.
         *
         * @return A new request builder for loading a {@link android.graphics.Bitmap}
         */
        public BitmapTypeRequest<ModelType> asBitmap() {
            return optionsApplier.apply(new BitmapTypeRequest<ModelType>(this, streamModelLoader,
                    fileDescriptorModelLoader, optionsApplier));
        }
    
        /**
         * Attempts to always load the resource as a {@link com.bumptech.glide.load.resource.gif.GifDrawable}.
         * <p>
         *     If the underlying data is not a GIF, this will fail. As a result, this should only be used if the model
         *     represents an animated GIF and the caller wants to interact with the GIfDrawable directly. Normally using
         *     just an {@link DrawableTypeRequest} is sufficient because it will determine whether or
         *     not the given data represents an animated GIF and return the appropriate animated or not animated
         *     {@link android.graphics.drawable.Drawable} automatically.
         * </p>
         *
         * @return A new request builder for loading a {@link com.bumptech.glide.load.resource.gif.GifDrawable}.
         */
        public GifTypeRequest<ModelType> asGif() {
            return optionsApplier.apply(new GifTypeRequest<ModelType>(this, streamModelLoader, optionsApplier));
        }
    
        ...
    }
    

    复制代码
    这个类中的代码本身就不多,我只是稍微做了一点简化。可以看到,最主要的就是它提供了 asBitmap() 和 asGif() 这两个方法。这两个方法我们在上一篇文章当中都是学过的,分别是用于强制指定加载静态图片和动态图片。而从源码中可以看出,它们分别又创建了一个 BitmapTypeRequest 和 GifTypeRequest,如果没有进行强制指定的话,那默认就是使用 DrawableTypeRequest。

    好的,那么我们再回到 RequestManager 的 load() 方法中。刚才已经分析过了,fromString() 方法会返回一个 DrawableTypeRequest 对象,接下来会调用这个对象的 load() 方法,把图片的 URL 地址传进去。但是我们刚才看到了,DrawableTypeRequest 中并没有 load() 方法,那么很容易就能猜想到,load() 方法是在父类当中的。
    <meta charset="utf-8">

    DrawableTypeRequest 的父类是 DrawableRequestBuilder,我们来看下这个类的源码:

    public class DrawableRequestBuilder<ModelType>
            extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
            implements BitmapOptions, DrawableOptions {
    
        DrawableRequestBuilder(Context context, Class<ModelType> modelClass,
                LoadProvider<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable> loadProvider, Glide glide,
                RequestTracker requestTracker, Lifecycle lifecycle) {
            super(context, modelClass, loadProvider, GlideDrawable.class, glide, requestTracker, lifecycle);
    
            crossFade();
        }
    
        public DrawableRequestBuilder<ModelType> thumbnail(
                DrawableRequestBuilder<?> thumbnailRequest) {
            super.thumbnail(thumbnailRequest);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> thumbnail(
                GenericRequestBuilder<?, ?, ?, GlideDrawable> thumbnailRequest) {
            super.thumbnail(thumbnailRequest);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> thumbnail(float sizeMultiplier) {
            super.thumbnail(sizeMultiplier);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> sizeMultiplier(float sizeMultiplier) {
            super.sizeMultiplier(sizeMultiplier);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> decoder(ResourceDecoder<ImageVideoWrapper, GifBitmapWrapper> decoder) {
            super.decoder(decoder);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> cacheDecoder(ResourceDecoder<File, GifBitmapWrapper> cacheDecoder) {
            super.cacheDecoder(cacheDecoder);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> encoder(ResourceEncoder<GifBitmapWrapper> encoder) {
            super.encoder(encoder);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> priority(Priority priority) {
            super.priority(priority);
            return this;
        }
    
        public DrawableRequestBuilder<ModelType> transform(BitmapTransformation... transformations) {
            return bitmapTransform(transformations);
        }
    
        public DrawableRequestBuilder<ModelType> centerCrop() {
            return transform(glide.getDrawableCenterCrop());
        }
    
        public DrawableRequestBuilder<ModelType> fitCenter() {
            return transform(glide.getDrawableFitCenter());
        }
    
        public DrawableRequestBuilder<ModelType> bitmapTransform(Transformation<Bitmap>... bitmapTransformations) {
            GifBitmapWrapperTransformation[] transformations =
                    new GifBitmapWrapperTransformation[bitmapTransformations.length];
            for (int i = 0; i < bitmapTransformations.length; i++) {
                transformations[i] = new GifBitmapWrapperTransformation(glide.getBitmapPool(), bitmapTransformations[i]);
            }
            return transform(transformations);
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> transform(Transformation<GifBitmapWrapper>... transformation) {
            super.transform(transformation);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> transcoder(
                ResourceTranscoder<GifBitmapWrapper, GlideDrawable> transcoder) {
            super.transcoder(transcoder);
            return this;
        }
    
        public final DrawableRequestBuilder<ModelType> crossFade() {
            super.animate(new DrawableCrossFadeFactory<GlideDrawable>());
            return this;
        }
    
        public DrawableRequestBuilder<ModelType> crossFade(int duration) {
            super.animate(new DrawableCrossFadeFactory<GlideDrawable>(duration));
            return this;
        }
    
        public DrawableRequestBuilder<ModelType> crossFade(int animationId, int duration) {
            super.animate(new DrawableCrossFadeFactory<GlideDrawable>(context, animationId,
                    duration));
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> dontAnimate() {
            super.dontAnimate();
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> animate(ViewPropertyAnimation.Animator animator) {
            super.animate(animator);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> animate(int animationId) {
            super.animate(animationId);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> placeholder(int resourceId) {
            super.placeholder(resourceId);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> placeholder(Drawable drawable) {
            super.placeholder(drawable);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> fallback(Drawable drawable) {
            super.fallback(drawable);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> fallback(int resourceId) {
            super.fallback(resourceId);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> error(int resourceId) {
            super.error(resourceId);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> error(Drawable drawable) {
            super.error(drawable);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> listener(
                RequestListener<? super ModelType, GlideDrawable> requestListener) {
            super.listener(requestListener);
            return this;
        }
        @Override
        public DrawableRequestBuilder<ModelType> diskCacheStrategy(DiskCacheStrategy strategy) {
            super.diskCacheStrategy(strategy);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> skipMemoryCache(boolean skip) {
            super.skipMemoryCache(skip);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> override(int width, int height) {
            super.override(width, height);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> sourceEncoder(Encoder<ImageVideoWrapper> sourceEncoder) {
            super.sourceEncoder(sourceEncoder);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> dontTransform() {
            super.dontTransform();
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> signature(Key signature) {
            super.signature(signature);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> load(ModelType model) {
            super.load(model);
            return this;
        }
    
        @Override
        public DrawableRequestBuilder<ModelType> clone() {
            return (DrawableRequestBuilder<ModelType>) super.clone();
        }
    
        @Override
        public Target<GlideDrawable> into(ImageView view) {
            return super.into(view);
        }
    
        @Override
        void applyFitCenter() {
            fitCenter();
        }
    
        @Override
        void applyCenterCrop() {
            centerCrop();
        }
    }
    复制代码
    
    

    DrawableRequestBuilder 中有很多个方法,这些方法其实就是 Glide 绝大多数的 API 了。里面有不少我们在上篇文章中已经用过了,比如说 placeholder() 方法、error() 方法、diskCacheStrategy() 方法、override() 方法等。当然还有很多暂时还没用到的 API,我们会在后面的文章当中学习。

    到这里,第二步 load() 方法也就分析结束了。为什么呢?因为你会发现 DrawableRequestBuilder 类中有一个 into() 方法(上述代码第 220 行),也就是说,最终 load() 方法返回的其实就是一个 DrawableTypeRequest 对象。

    接下来我们就要进行第三步了,由于篇幅有限,将在下一篇分析 into() 方法中的逻辑。

    为了方便大家更深入的学习第三框架。我整理了一份《设计思想解读开源框架》,有需要的伙伴可以点赞+关注后,点击这里直接获取

    image

    作者:郭霖
    链接:https://juejin.cn/post/6913799833841041422
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    相关文章

      网友评论

          本文标题:Android图片加载框架解析(二):从源码的角度理解Glide

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