In the last article in this series, we learned the basics of Glide, experienced the power of the image-loading framework, and its very simple API. Have not read the last article friends, suggested to read the Android picture loading framework most complete analysis (a), Glide basic usage.

In most cases, we want to load and display an image on the interface with just one line of code, like this:

Glide.with(this).load(url).into(imageView);
Copy the code

It’s a simple line of code, but what you may not know is that Glide is doing tons of work behind the scenes for us. I have thought about this adjective for a long time, because I feel that the adjective “tons of work” is not enough to describe the work behind Glide. The English material I found is tons of work, so I think it is more appropriate to use tons of work.

Although we use Glide in peacetime is particularly simple and convenient, but also to know why. So today we are going to parse the source code for Glide and see how complex it is behind these simple uses.

How to read source code

Before beginning to parse Glide source, I would like to talk to you about how to read the source code, this problem is I am usually asked more, because a lot of people feel that reading the source code is a more difficult thing.

So is it difficult to read the source code? This, of course, depends on the source code. For example, the same image loading framework, I read Volley source code feel happy, and Volley architecture design and code quality deeply admire. Glide read the source code but let me quite painful, the code is extremely difficult to understand. I’m not saying Glide is bad code here, but Glide is not on the same level of complexity as Volley.

So while the complexity of source code is an external immutable condition, there are a few tricks you can use to improve your ability to read it. Here I share with you my usual reading source code when the use of skills, a simple summary is eight words: the silk, point to stop. Identify a function point and analyze how that function point is implemented. Instead of trying to figure out what every line of code means, just follow the implementation logic of the subject. It’s easy to get stuck in a mental black hole, and get stuck deeper and deeper. Because these huge systems are not written by a single person, every line of code to understand, you will feel like a blind man touching an elephant, will never be able to understand. If only to analyze the implementation logic of the subject, then there is a clearer purpose, so that reading the source code will be easier and more productive.

And today with you to read the Glide source code is very suitable for the use of this skill, because Glide source is too complex, do not try to figure out the role of each line of code, but should only analyze its main implementation logic. So we set a goal for this article, is to read the source code to understand the following line of code:

Glide.with(this).load(url).into(imageView);
Copy the code

How to display a web image onto ImageView. Glide first a set of picture loading mechanism of the basic process of comb clear, and then we through the following several articles to understand the details of Glide source code aspects.

Are you ready? So let’s get started.

Download the source code

Since it is to read the source Glide, so we naturally need to download the source Glide first. If you add Glide to your project by adding dependencies to build.gradle, the source code is automatically downloaded and can be viewed directly in Android Studio.

Glide, however, can only see the source code, but can’t make any changes to it. If you still need to modify the source code, you can download the full source code on GitHub.

Glide’s GitHub home page is github.com/bumptech/gl…

However, the source code downloaded from this address is always the latest, and may still be under development. Glide 3.7.0 is used in this series, so if you need to download the 3.7.0 version of the source code, you can download it here: github.com/bumptech/gl…

Start reading

Glide we learned in the last article that the most basic use of Glide is three steps: first with(), then load(), and finally into(). So let’s start by reading the source code for the three steps, starting with with().

  1. with()

The With () method is a set of static methods in the Glide class. It has several method overloads. Let’s look at all the method overloads in the Glide class:

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); }}Copy the code

As you can see, the with() method has a wide variety of overloads. You can pass in activities, fragments or contexts. The code for each with() method overload is very simple, starting with a call to the RequestManagerRetriever retriever static get() method, which is a singleton implementation. There’s nothing to explain. You can then call the Get () method on the RequestManagerRetriever instance to obtain the RequestManager object.

What about the logic in the get() method of the RequestManagerRetriever instance? Let’s take a look:

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

    ...
}
Copy the code

The above code may seem logically complex, but when you tease it out, it’s pretty simple. In the RequestManagerRetriever class, there may be multiple overloads of get() methods, including Context parameters, Activity parameters, Fragment parameters, and so on. And pass in parameters that are not of Application type.

Let’s first look at passing in the Application parameter. If an Application object is passed in the Glide. With () method, then the get() method overload with the Context parameter is called, The getApplicationManager() method is then called at line 44 to get a RequestManager object. This is actually the simplest case, because the life of the Application object is the life of the Application, so Glide doesn’t need to do anything special. It is automatically synchronized with the life of the Application, and if the Application is shut down, Glide’s load terminates at the same time.

Let’s look at passing in non-application parameters. Whether you pass an Activity, FragmentActivity, Fragment from a V4 package, or Fragment from an APP package in the Glide. With () method, the final flow is the same. Add a hidden Fragment to the current Activity. The added logic is in line 117 and 141 of the code above, corresponding to the two fragments in the APP package and v4 package, respectively. So why add a hidden Fragment here? Glide needs to know the life cycle of the load. If you’re loading an image on an Activity and the user shuts it down before the image is loaded, should the image load again? Of course not. But Glide has no way of knowing the life cycle of an Activity, so It uses the trick of adding a hidden Fragment, because the Fragment life cycle is synchronized with the Activity, and if the Activity is destroyed, Fragment can be heard so that Glide can catch the event and stop the image loading.

As an extra note, line 48 shows that if you use Glide on a non-mainline thread, any incoming Activity or Fragment will be forced to be treated as an Application. But in fact, this is the analysis of the details of the code, this article we will focus on the main line of Glide workflow above, not too much to analyze these details.

Overall, the source code for the first with() method is fairly easy to understand. It’s all about getting a RequestManager object, and Glide will use the parameters we passed to the with() method to determine the image load lifecycle, without any particularly complicated logic. But the complicated logic still awaits us, so let’s look at the second step, the load() method.

  1. load()

Since the with() method returns a RequestManager object, it is easy to assume that the load() method is in the RequestManager class, so the first thing to look at is the RequestManager class. But as we learned in the last article, Glide supports image URL strings, image local paths, and so on, so there are a number of overloaded load() methods in the RequestManager. It’s not possible to look at every overload of the load() method here, so let’s look at just one load() method that loads the image URL string.

The simplified code for the RequestManager class looks like this:

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)); }... }Copy the code

The code for the RequestManager class is quite extensive, but after simplifying like this, it looks clean. While we’re only exploring the load() method of loading the image URL string, the only important methods are the three in the code above.

So let’s look at the load() method. The logic in this method is very simple, just one line of code, first calls the fromString() method, then calls the load() method, then passes in the image URL. The fromString() method is also extremely simple, calling the loadGeneric() method and specifying string.class because the load() method passes in a String argument. So it looks as if the main work is done in the loadGeneric() method.

The loadGeneric() method doesn’t have many lines of code, There are calls the Glide. BuildStreamModelLoader () method and Glide buildFileDescriptorModelLoader () method to obtain ModelLoader object. The ModelLoader object is used to load images, and if we pass different types of arguments to the load() method, we get different ModelLoader objects. However, the logic inside the buildStreamModelLoader() method is pretty complicated, so I won’t go into it here, or I won’t have the space to do it myself. Since the argument we just passed was String.class, we end up with a StreamStringLoader object that implements the ModelLoader interface.

The loadGeneric() method returns a DrawableTypeRequest, so at the end of the loadGeneric() method a new DrawableTypeRequest is added. I then passed in the ModelLoader object I just got, along with a bunch of other stuff. The specific meaning and function of each parameter are not explained, we only look at the main flow.

So what does this DrawableTypeRequest do? Let’s take a look at its source code, as follows:

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)); }... }Copy the code

There isn’t much code in this class, so I’m just simplifying it a little bit. As you can see, the main thing is that it provides the asBitmap() and asGif() methods. We learned about both methods in the previous article, which are used to force the loading of static images and dynamic images. In the source code, they create BitmapTypeRequest and GifTypeRequest, respectively, which default to DrawableTypeRequest if not specified.

Ok, so let’s go back to the Load () method in the RequestManager. As you’ve just analyzed, the fromString() method returns a DrawableTypeRequest object, which then calls its load() method, passing in the image URL. But as we just saw, the DrawableTypeRequest doesn’t have a load() method, so it’s easy to guess that the load() method is in the parent class.

Equestbuilder class: DrawableTypeRequest and equestBuilder.

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();
    }
}
Copy the code

There are a number of equestbuilder methods that are part of Glide’s API. Some of them we’ve already used in the previous article, such as placeholder(), error(), diskCacheStrategy(), override(), and more. Of course, there are many other apis that haven’t been used yet, which we’ll learn about in a later article.

This completes the analysis of the second load() method. Why is that? As you can see from the equestBuilder class of DrawableRequestBuilder there is a into() method (line 220 above), which means that the load() method returns a DrawableTypeRequest object.

Next we move on to step 3, which, due to space constraints, will look at the logic in the into() method in the next article.