Source code analysis--Glide source code loading picture one with and load

written in front

It’s been a while since I wrote a blog. I read some miscellaneous things in the middle, and I also passed some interview questions. By the way, I read all interview questions on Wanandroid’s https://www.wanandroid.com/ , there are many classifications and relatively complete, it is recommended to collect

Open Baidu to search Gilde source code, and there will be millions of search results, but why should I write this blog again?

First, it can guide the way for those who come later. The second is to improve your ability to express and communicate even when retelling, and the third is to strengthen your understanding. Even if you forget later, you can quickly recall everything in the code through this article.

In terms of these three points, the first point is the smallest point, and the focus is on the second and third points.

For Glide, a lot of reuse, transformation, etc. are used in the code, so it is recommended that you save the code you see in cloud notes when looking at the source code, so that it is easy to go back.


For the Glide source code, this should also be a new pit, because the space will definitely not be finished at one time, the specific number of sections may depend on the specific situation


For the first Glide source code analysis, the most important thing is to go through the complete network request process, and the Glide version is 3.7.0. Because this is the version I used for the first time when I came into contact with Glide, and I have seen some of the code before. In order to save trouble, I chose this version

First, let's take a look at how to use Glide

String s = "https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=1066881363,1963636720&fm=173&app=25&f=JPEG?w=639&h=426&s=BF104C810E535FD624B4D89F0300C080";
Glide.with(MainActivity.this).load(s).into(imageView);

This is the most basic method of use. It is divided into three steps: with, load, and into. Let's look at them one by one.

with

    public static RequestManager with(FragmentActivity activity) {
    
    
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(activity);
    }
 
 	public RequestManager get(FragmentActivity activity) {
    
    
        if (Util.isOnBackgroundThread()) {
    
    
        //如果不在主线程复用get(context)的方法
            return get(activity.getApplicationContext());
        } else {
    
    
            assertNotDestroyed(activity);
            //获取出一个FragmentManager来监听Activity的生命周期
            FragmentManager fm = activity.getSupportFragmentManager();
            return supportFragmentGet(activity, fm);
        }
    }
	
	//关键代码
	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;
    }

Obtain a SupportRequestManagerFragment object through fm, let's see how this is obtained

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

The logic here is relatively clear. Create a blank Fragment through fm, and monitor the life cycle of this Fragment through the interface. The specific implementation can be learned by looking at the SupportRequestManagerFragment constructor.
read on

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

At the beginning, a RequestManager object was created and returned. Let's take a look at the constructor of RequestManager

public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
    
    
        this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
    }

    RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
            RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
    
    
        this.context = context.getApplicationContext();
        this.lifecycle = lifecycle;
        this.treeNode = treeNode;
        this.requestTracker = requestTracker;
        //初始话了Glide
        this.glide = Glide.get(context);
        this.optionsApplier = new OptionsApplier();

        ConnectivityMonitor connectivityMonitor = factory.build(context,
                new RequestManagerConnectivityListener(requestTracker));
        if (Util.isOnBackgroundThread()) {
    
    
            new Handler(Looper.getMainLooper()).post(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    lifecycle.addListener(RequestManager.this);
                }
            });
        } else {
    
    
            lifecycle.addListener(this);
        }
        lifecycle.addListener(connectivityMonitor);
    }

You can see that the initial words of some data are made here, and the most important one is the initial words of Glide. We can take a look at the initial words of Glide.

 public static Glide get(Context context) {
    
    
        if (glide == null) {
    
    
            synchronized (Glide.class) {
    
    
                if (glide == null) {
    
    
                    Context applicationContext = context.getApplicationContext();
                    List<GlideModule> modules = new ManifestParser(applicationContext).parse();

                    GlideBuilder builder = new GlideBuilder(applicationContext);
                    for (GlideModule module : modules) {
    
    
                        module.applyOptions(applicationContext, builder);
                    }
                    glide = builder.createGlide();
                    for (GlideModule module : modules) {
    
    
                        module.registerComponents(applicationContext, glide);
                    }
                }
            }
        }

        return glide;
    }

	    Glide createGlide() {
    
    
        if (sourceService == null) {
    
    
            final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
            sourceService = new FifoPriorityThreadPoolExecutor(cores);
        }
        if (diskCacheService == null) {
    
    
            diskCacheService = new FifoPriorityThreadPoolExecutor(1);
        }

        MemorySizeCalculator calculator = new MemorySizeCalculator(context);
        if (bitmapPool == null) {
    
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    
    
                int size = calculator.getBitmapPoolSize();
                bitmapPool = new LruBitmapPool(size);
            } else {
    
    
                bitmapPool = new BitmapPoolAdapter();
            }
        }

        if (memoryCache == null) {
    
    
            memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
        }

        if (diskCacheFactory == null) {
    
    
            diskCacheFactory = new InternalCacheDiskCacheFactory(context);
        }

        if (engine == null) {
    
    
            engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
        }

        if (decodeFormat == null) {
    
    
            decodeFormat = DecodeFormat.DEFAULT;
        }

        return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
    }

	 Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
    
    
        this.engine = engine;
        this.bitmapPool = bitmapPool;
        this.memoryCache = memoryCache;
        this.decodeFormat = decodeFormat;
        loaderFactory = new GenericLoaderFactory(context);
        mainHandler = new Handler(Looper.getMainLooper());
        bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);

        dataLoadProviderRegistry = new DataLoadProviderRegistry();

        StreamBitmapDataLoadProvider streamBitmapLoadProvider =
                new StreamBitmapDataLoadProvider(bitmapPool, decodeFormat);
        dataLoadProviderRegistry.register(InputStream.class, Bitmap.class, streamBitmapLoadProvider);

        FileDescriptorBitmapDataLoadProvider fileDescriptorLoadProvider =
                new FileDescriptorBitmapDataLoadProvider(bitmapPool, decodeFormat);
        dataLoadProviderRegistry.register(ParcelFileDescriptor.class, Bitmap.class, fileDescriptorLoadProvider);

        ImageVideoDataLoadProvider imageVideoDataLoadProvider =
                new ImageVideoDataLoadProvider(streamBitmapLoadProvider, fileDescriptorLoadProvider);
        dataLoadProviderRegistry.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider);

        GifDrawableLoadProvider gifDrawableLoadProvider =
                new GifDrawableLoadProvider(context, bitmapPool);
        dataLoadProviderRegistry.register(InputStream.class, GifDrawable.class, gifDrawableLoadProvider);

        dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class,
                new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider, gifDrawableLoadProvider, bitmapPool));

        dataLoadProviderRegistry.register(InputStream.class, File.class, new StreamFileDataLoadProvider());

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

        transcoderRegistry.register(Bitmap.class, GlideBitmapDrawable.class,
                new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool));
        transcoderRegistry.register(GifBitmapWrapper.class, GlideDrawable.class,
                new GifBitmapWrapperDrawableTranscoder(
                        new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool)));

        bitmapCenterCrop = new CenterCrop(bitmapPool);
        drawableCenterCrop = new GifBitmapWrapperTransformation(bitmapPool, bitmapCenterCrop);

        bitmapFitCenter = new FitCenter(bitmapPool);
        drawableFitCenter = new GifBitmapWrapperTransformation(bitmapPool, bitmapFitCenter);
    }

There are a lot of initial words here, including the disk cache and memory cache in the third-level image cache, and some methods of registration. I won’t expand here. We only need to understand these things.
Basically, the first with method is finished here. Let’s summarize the content of with:
1. Obtain the fragmentManager passed in to the Activity, and create a blank fragment to monitor the life cycle of the Activity, and finally encapsulate the A requestManager
2. Initially, there are a lot of parameters, including Glide itself, disk cache and memory cache.

load

First look at the usage of load

load("https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=1066881363,1963636720&fm=173&app=25&f=JPEG?w=639&h=426&s=BF104C810E535FD624B4D89F0300C080")

The incoming type is String, look at the specific implementation of this code

 public DrawableTypeRequest<File> load(File file) {
    
    
        return (DrawableTypeRequest<File>) fromFile().load(file);
    }

 public DrawableTypeRequest<Uri> loadFromMediaStore(Uri uri) {
    
    
        return (DrawableTypeRequest<Uri>) fromMediaStore().load(uri);
    }
       public DrawableTypeRequest<Integer> load(Integer resourceId) {
    
    
        return (DrawableTypeRequest<Integer>) fromResource().load(resourceId);
    }
    public DrawableTypeRequest<URL> load(URL url) {
    
    
        return (DrawableTypeRequest<URL>) fromUrl().load(url);
    }
        public DrawableTypeRequest<String> load(String string) {
    
    
        return (DrawableTypeRequest<String>) fromString().load(string);
    }

This method has multiple overloads. For the specific implementation of the method of passing in String, we mainly focus on the fromString() method.

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

The value of the last return here can be regarded as new DrawableTypeRequest. A large amount of data construction is completed here. The two ModelLoaders created will not be discussed here. The specific words will be related to the register method in the Glide constructor in the previous step. The specific returned value is HttpUrlGlideUrlLoader. Next, look at the constructor of DrawableTypeRequest

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

Pay attention to the buildProvider method

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

A FixedLoadProvider object is returned, which will be used for recording later.

Due to the space, let’s talk about it here for the time being. To sum up, with and load are mainly the initialization parameters for Glide. In addition, with will create a FragmentManager for the current page, and then use this fm to create an empty fragment to update this page. , In addition, the with method also initializes Glide and registers the corresponding moderLoader. And load mainly determines the corresponding moderLoader according to the parameters passed in.

Guess you like

Origin blog.csdn.net/just_hu/article/details/106407592