A recent search while working on some issues revealed that the vast majority of articles are based on 3.x. It is two or three years since Glide entered 4.x, and many changes have taken place on the basis of 3.x. Fortunately, I am familiar with 4.X source code, and Glide design is also very wonderful, simply write a write to 4.X analysis.

Of course, for most readers, because there is a certain amount of basic knowledge, these analysis articles are not all over the ground, you can read the leak.

Think again series is my latest study, summary form, focus on: problem analysis, technology accumulation, vision expansion, know more

This paper purpose

Glide is alargeThis article is designed to be carried out on the 4.x version of Glide ProjectAll-round cognition

Specific for: understand Glide processing which problems, which modules and its corresponding

For readers familiar with Square’s open-source Picasso from the early days, it’s not hard to understand: Picasso is a small but elegant framework that focuses on the following four main issues with image loading:

  • Asynchronous process management and scheduling
  • Resources and display container many-to-many relationships
  • Multistage cache
  • Image conversion supports ScaleType

Glide, a newcomer, has been a broad and detailed framework for loading images asynchronously.

During the Glide 1.x era, the two had similar concerns, and with the development of officially supported Glide, its concerns have increased, including but not limited to:

  • Resource encapsulation
  • Resource acquisition method and process
  • The cache
  • decode,encodeThe process of
  • The Target of the abstract.Note: The ultimate goal of media resource acquisition, such as saving as a file, loading into ImageView medium
  • Image conversion
  • Many-to-many relationship between resource and Target
  • Life cycle awareness and control

When you think about all of these points, it’s not hard to see that Glide has set its sights on solving this problem:

Build a system, the designated identification media resources of the entity, its encapsulation form can be self-expansion, the implementation of resource acquisition, and the application of memory, disk caching, encapsulation of the picture decoding process, according to the specified requirements for cutting, scaling and other picture conversion, and finally the results applied to the specified target. And the entire process according to the Characteristics of the Android platform for life cycle management.

Most nodes, or sections, in this process can be externally extended

This point can be confirmed from the project introduction: just look at the key words

Glide is a fast and efficient open source media management and image loading framework for Android that wraps media decoding, memory and disk caching, and resource pooling into a simple and easy to use interface.

Glide supports fetching, decoding, and displaying video stills, images, and animated GIFs. Glide includes a flexible API that allows developers to plug in to almost any network stack. By default Glide uses a custom HttpUrlConnection based stack, but also includes utility libraries plug in to Google’s Volley project or Square’s OkHttp library instead.

Glide’s primary focus is on making scrolling any kind of a list of images as smooth and fast as possible, but Glide is also effective for almost any case where you need to fetch, resize, and display a remote image.

Module responsibility division, peep from Glide’s construction process

It is easy to understand that a large system needs to divide responsibilities on the basis of SRP, so that classes will become too many and the construction process will become complicated. The Builder mode can solve this problem well.

class GlideBuilder {
    public Glide build(@NonNull Context context) {
        if (sourceExecutor == null) {
            sourceExecutor = GlideExecutor.newSourceExecutor();
        }

        if (diskCacheExecutor == null) {
            diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
        }

        if (animationExecutor == null) {
            animationExecutor = GlideExecutor.newAnimationExecutor();
        }

        if (memorySizeCalculator == null) {
            memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
        }

        if (connectivityMonitorFactory == null) {
            connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
        }

        if (bitmapPool == null) {
            int size = memorySizeCalculator.getBitmapPoolSize();
            if (size > 0) {
                bitmapPool = new LruBitmapPool(size);
            } else {
                bitmapPool = newBitmapPoolAdapter(); }}if (arrayPool == null) {
            arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
        }

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

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

        if (engine == null) {
            engine = new Engine(
                    memoryCache,
                    diskCacheFactory,
                    diskCacheExecutor,
                    sourceExecutor,
                    GlideExecutor.newUnlimitedSourceExecutor(),
                    GlideExecutor.newAnimationExecutor(),
                    isActiveResourceRetentionAllowed);
        }

        RequestManagerRetriever requestManagerRetriever =
                new RequestManagerRetriever(requestManagerFactory);

        return newGlide( context, engine, memoryCache, bitmapPool, arrayPool, requestManagerRetriever, connectivityMonitorFactory, logLevel, defaultRequestOptions.lock(), defaultTransitionOptions); }}Copy the code

From here we can gather the following valid information

  • Cache and pool
    • MemorySizeCalculator
    • LruBitmapPool
    • BitmapPoolAdapter
    • LruArrayPool
    • LruResourceCache
    • InternalCacheDiskCacheFactory
  • The resource acquisition
    • RequestManagerRetriever
    • DefaultConnectivityMonitorFactory
  • Core Process Management
    • Engine
  • The thread pool
    • GlideExecutor

Constructors: The code is long, leaving out some of the content

class Glide {
    Glide(
            @NonNull Context context,
            @NonNull Engine engine,
            @NonNull MemoryCache memoryCache,
            @NonNull BitmapPool bitmapPool,
            @NonNull ArrayPool arrayPool,
            @NonNull RequestManagerRetriever requestManagerRetriever,
            @NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
            int logLevel,
            @NonNull RequestOptions defaultRequestOptions,
            @NonNullMap<Class<? >, TransitionOptions<? ,? >> defaultTransitionOptions) {this.engine = engine;
        this.bitmapPool = bitmapPool;
        this.arrayPool = arrayPool;
        this.memoryCache = memoryCache;
        this.requestManagerRetriever = requestManagerRetriever;
        this.connectivityMonitorFactory = connectivityMonitorFactory;

        DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT);
        bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);

        final Resources resources = context.getResources();

        registry = new Registry();
        registry.register(new DefaultImageHeaderParser());

        Downsampler downsampler = new Downsampler(registry.getImageHeaderParsers(),
                resources.getDisplayMetrics(), bitmapPool, arrayPool);
        ByteBufferGifDecoder byteBufferGifDecoder =
                new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), bitmapPool, arrayPool);
        ResourceDecoder<ParcelFileDescriptor, Bitmap> parcelFileDescriptorVideoDecoder =
                VideoDecoder.parcel(bitmapPool);
        ByteBufferBitmapDecoder byteBufferBitmapDecoder = new ByteBufferBitmapDecoder(downsampler);
        StreamBitmapDecoder streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool);
        ResourceDrawableDecoder resourceDrawableDecoder =
                new ResourceDrawableDecoder(context);
        ResourceLoader.StreamFactory resourceLoaderStreamFactory =
                new ResourceLoader.StreamFactory(resources);
        ResourceLoader.UriFactory resourceLoaderUriFactory =
                new ResourceLoader.UriFactory(resources);
        ResourceLoader.FileDescriptorFactory resourceLoaderFileDescriptorFactory =
                new ResourceLoader.FileDescriptorFactory(resources);
        ResourceLoader.AssetFileDescriptorFactory resourceLoaderAssetFileDescriptorFactory =
                new ResourceLoader.AssetFileDescriptorFactory(resources);
        BitmapEncoder bitmapEncoder = new BitmapEncoder(arrayPool);

        BitmapBytesTranscoder bitmapBytesTranscoder = new BitmapBytesTranscoder();
        GifDrawableBytesTranscoder gifDrawableBytesTranscoder = new GifDrawableBytesTranscoder();

        ContentResolver contentResolver = context.getContentResolver();

        registry
                .append(ByteBuffer.class, new ByteBufferEncoder())
                /* omit a paragraph, too long */
                .register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);

        ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
        glideContext =
                newGlideContext( context, arrayPool, registry, imageViewTargetFactory, defaultRequestOptions, defaultTransitionOptions, engine, logLevel); }}Copy the code

This paragraph can be broken down into immediate parts:

  • The field value of builder is assigned
  • Build non-openBitmapPreFillerThe instance
  • buildRegistryThe instanceregistry
  • buildDefaultImageHeaderParserResourceLoaderDecoderResourceTranscoderAnd register it toregistry
  • buildGlideContextThe instanceglideContext

As a rule of thumb, Registry is a policy Registry that serves the policy schema.

It is not difficult to understand that Glide’s working environment is very complex. For example, to acquire resources, the location of the resources may be in a certain location in the network, in the Assets of the application, or in other locations. For a certain goal, there are different implementation strategies according to different scenarios

As a further rule of thumb, registries are divided into different policy groups with different goals, which we will look at later.

Follow the initialization process as we usually do: read extensively

class Glide {
    public static Glide get(@NonNull Context context) {
        if (glide == null) {
            synchronized (Glide.class) {
                if (glide == null) { checkAndInitializeGlide(context); }}}return glide;
    }

    private static void checkAndInitializeGlide(@NonNull Context context) {
        / /...
        initializeGlide(context);
        / /...
    }

    // omit the overload
    public static RequestManager with(@NonNull Activity activity) {
        return getRetriever(activity).get(activity);
    }

    @NonNull
    private static RequestManagerRetriever getRetriever(@Nullable Context context) {
        // Context could be null for other reasons (ie the user passes in null), but in practice it will
        // only occur due to errors with the Fragment lifecycle.
        Preconditions.checkNotNull(
                context,
                "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
                        + "returns null (which usually occurs when getActivity() is called before the Fragment "
                        + "is attached or after the Fragment is destroyed).");
        returnGlide.get(context).getRequestManagerRetriever(); }}Copy the code

Glide. With (…) Began to get RequestManager, of course, also can to Glide. Get (context). GetRequestManagerRetriever () method. If Glide is not initialized, initializeGlide is called to initialize it.

Follow up on the code and read it extensively

class Glide {
    private static void initializeGlide(@NonNull Context context) {
        initializeGlide(context, new GlideBuilder());
    }

    @SuppressWarnings("deprecation")
    private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
        Context applicationContext = context.getApplicationContext();
        GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
        List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
        if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
            manifestModules = new ManifestParser(applicationContext).parse();
        }

        if(annotationGeneratedModule ! =null&&! annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) { Set<Class<? >> excludedModuleClasses = annotationGeneratedModule.getExcludedModuleClasses(); Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
            while (iterator.hasNext()) {
                com.bumptech.glide.module.GlideModule current = iterator.next();
                if(! excludedModuleClasses.contains(current.getClass())) {continue;
                }
                if (Log.isLoggable(TAG, Log.DEBUG)) {
                    Log.d(TAG, "AppGlideModule excludes manifest GlideModule: "+ current); } iterator.remove(); }}if (Log.isLoggable(TAG, Log.DEBUG)) {
            for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
                Log.d(TAG, "Discovered GlideModule from manifest: "+ glideModule.getClass()); } } RequestManagerRetriever.RequestManagerFactory factory = annotationGeneratedModule ! =null
                        ? annotationGeneratedModule.getRequestManagerFactory() : null;
        builder.setRequestManagerFactory(factory);
        for (com.bumptech.glide.module.GlideModule module : manifestModules) {
            module.applyOptions(applicationContext, builder);
        }
        if(annotationGeneratedModule ! =null) {
            annotationGeneratedModule.applyOptions(applicationContext, builder);
        }
        Glide glide = builder.build(applicationContext);
        for (com.bumptech.glide.module.GlideModule module : manifestModules) {
            module.registerComponents(applicationContext, glide, glide.registry);
        }
        if(annotationGeneratedModule ! =null) { annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry); } applicationContext.registerComponentCallbacks(glide); Glide.glide = glide; }}Copy the code

After extensive reading, we find that there are three main steps:

  • Build GlideBuilder
  • By reflection, loadThere may beCustom module, set to Builder
  • Build the Glide

Caution: If you build directly with GlideBuilder, you will not be able to directly use the contents of the custom modules and will need to inject them yourself.

Module responsibility division, details in Register

In the previous section, we left out some details of the Glide instantiation process, which is implemented by registering various modules with the Register. You can read the source code:

 registry
        .append(ByteBuffer.class,new ByteBufferEncoder())
        .append(InputStream.class,new StreamEncoder(arrayPool))
        /* Bitmaps */
        .append(Registry.BUCKET_BITMAP,ByteBuffer.class,Bitmap.class,byteBufferBitmapDecoder)
        .append(Registry.BUCKET_BITMAP,InputStream.class,Bitmap.class,streamBitmapDecoder)
        .append(
        Registry.BUCKET_BITMAP,
        ParcelFileDescriptor.class,
        Bitmap.class,
        parcelFileDescriptorVideoDecoder)
        .append(
        Registry.BUCKET_BITMAP,
        AssetFileDescriptor.class,
        Bitmap.class,
        VideoDecoder.asset(bitmapPool))
        .append(Bitmap.class,Bitmap.class,UnitModelLoader.Factory.<Bitmap>getInstance())
        .append(
        Registry.BUCKET_BITMAP,Bitmap.class,Bitmap.class,new UnitBitmapDecoder())
        .append(Bitmap.class,bitmapEncoder)
        /* BitmapDrawables */
        .append(
        Registry.BUCKET_BITMAP_DRAWABLE,
        ByteBuffer.class,
        BitmapDrawable.class,
        new BitmapDrawableDecoder<>(resources,byteBufferBitmapDecoder))
        .append(
        Registry.BUCKET_BITMAP_DRAWABLE,
        InputStream.class,
        BitmapDrawable.class,
        new BitmapDrawableDecoder<>(resources,streamBitmapDecoder))
        .append(
        Registry.BUCKET_BITMAP_DRAWABLE,
        ParcelFileDescriptor.class,
        BitmapDrawable.class,
        new BitmapDrawableDecoder<>(resources,parcelFileDescriptorVideoDecoder))
        .append(BitmapDrawable.class,new BitmapDrawableEncoder(bitmapPool,bitmapEncoder))
        /* GIFs */
        .append(
        Registry.BUCKET_GIF,
        InputStream.class,
        GifDrawable.class,
        new StreamGifDecoder(registry.getImageHeaderParsers(),byteBufferGifDecoder,arrayPool))
        .append(Registry.BUCKET_GIF,ByteBuffer.class,GifDrawable.class,byteBufferGifDecoder)
        .append(GifDrawable.class,new GifDrawableEncoder())
        /* GIF Frames */
        // Compilation with Gradle requires the type to be specified for UnitModelLoader here.
        .append(
        GifDecoder.class,GifDecoder.class,UnitModelLoader.Factory.<GifDecoder>getInstance())
        .append(
        Registry.BUCKET_BITMAP,
        GifDecoder.class,
        Bitmap.class,
        new GifFrameResourceDecoder(bitmapPool))
        /* Drawables */
        .append(Uri.class,Drawable.class,resourceDrawableDecoder)
        .append(
        Uri.class,Bitmap.class,new ResourceBitmapDecoder(resourceDrawableDecoder,bitmapPool))
        /* Files */
        .register(new ByteBufferRewinder.Factory())
        .append(File.class,ByteBuffer.class,new ByteBufferFileLoader.Factory())
        .append(File.class,InputStream.class,new FileLoader.StreamFactory())
        .append(File.class,File.class,new FileDecoder())
        .append(File.class,ParcelFileDescriptor.class,new FileLoader.FileDescriptorFactory())
        // Compilation with Gradle requires the type to be specified for UnitModelLoader here.
        .append(File.class,File.class,UnitModelLoader.Factory.<File>getInstance())
        /* Models */
        .register(new InputStreamRewinder.Factory(arrayPool))
        .append(int.class,InputStream.class,resourceLoaderStreamFactory)
        .append(
        int.class,
        ParcelFileDescriptor.class,
        resourceLoaderFileDescriptorFactory)
        .append(Integer.class,InputStream.class,resourceLoaderStreamFactory)
        .append(
        Integer.class,
        ParcelFileDescriptor.class,
        resourceLoaderFileDescriptorFactory)
        .append(Integer.class,Uri.class,resourceLoaderUriFactory)
        .append(
        int.class,
        AssetFileDescriptor.class,
        resourceLoaderAssetFileDescriptorFactory)
        .append(
        Integer.class,
        AssetFileDescriptor.class,
        resourceLoaderAssetFileDescriptorFactory)
        .append(int.class,Uri.class,resourceLoaderUriFactory)
        .append(String.class,InputStream.class,new DataUrlLoader.StreamFactory())
        .append(String.class,InputStream.class,new StringLoader.StreamFactory())
        .append(String.class,ParcelFileDescriptor.class,new StringLoader.FileDescriptorFactory())
        .append(
        String.class,AssetFileDescriptor.class,new StringLoader.AssetFileDescriptorFactory())
        .append(Uri.class,InputStream.class,new HttpUriLoader.Factory())
        .append(Uri.class,InputStream.class,new AssetUriLoader.StreamFactory(context.getAssets()))
        .append(
        Uri.class,
        ParcelFileDescriptor.class,
        new AssetUriLoader.FileDescriptorFactory(context.getAssets()))
        .append(Uri.class,InputStream.class,new MediaStoreImageThumbLoader.Factory(context))
        .append(Uri.class,InputStream.class,new MediaStoreVideoThumbLoader.Factory(context))
        .append(
        Uri.class,
        InputStream.class,
        new UriLoader.StreamFactory(contentResolver))
        .append(
        Uri.class,
        ParcelFileDescriptor.class,
        new UriLoader.FileDescriptorFactory(contentResolver))
        .append(
        Uri.class,
        AssetFileDescriptor.class,
        new UriLoader.AssetFileDescriptorFactory(contentResolver))
        .append(Uri.class,InputStream.class,new UrlUriLoader.StreamFactory())
        .append(URL.class,InputStream.class,new UrlLoader.StreamFactory())
        .append(Uri.class,File.class,new MediaStoreFileLoader.Factory(context))
        .append(GlideUrl.class,InputStream.class,new HttpGlideUrlLoader.Factory())
        .append(byte[].class,ByteBuffer.class,new ByteArrayLoader.ByteBufferFactory())
        .append(byte[].class,InputStream.class,new ByteArrayLoader.StreamFactory())
        .append(Uri.class,Uri.class,UnitModelLoader.Factory.<Uri>getInstance())
        .append(Drawable.class,Drawable.class,UnitModelLoader.Factory.<Drawable>getInstance())
        .append(Drawable.class,Drawable.class,new UnitDrawableDecoder())
        /* Transcoders */
        .register(
        Bitmap.class,
        BitmapDrawable.class,
        new BitmapDrawableTranscoder(resources))
        .register(Bitmap.class,byte[].class,bitmapBytesTranscoder)
        .register(
        Drawable.class,
        byte[].class,
        new DrawableBytesTranscoder(
        bitmapPool,bitmapBytesTranscoder,gifDrawableBytesTranscoder))
        .register(GifDrawable.class,byte[].class,gifDrawableBytesTranscoder);
Copy the code

It’s pointless to go through this code directly, so let’s start with the Register class and analyze the contents of the Register.

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

    private final ModelLoaderRegistry modelLoaderRegistry;
    private final EncoderRegistry encoderRegistry;
    private final ResourceDecoderRegistry decoderRegistry;
    private final ResourceEncoderRegistry resourceEncoderRegistry;
    private final DataRewinderRegistry dataRewinderRegistry;
    private final TranscoderRegistry transcoderRegistry;
    private final ImageHeaderParserRegistry imageHeaderParserRegistry;

    private final ModelToResourceClassCache modelToResourceClassCache =
            new ModelToResourceClassCache();
    private final LoadPathCache loadPathCache = new LoadPathCache();
    private final Pool<List<Throwable>> throwableListPool = FactoryPools.threadSafeList();

    public Registry(a) {
        this.modelLoaderRegistry = new ModelLoaderRegistry(throwableListPool);
        this.encoderRegistry = new EncoderRegistry();
        this.decoderRegistry = new ResourceDecoderRegistry();
        this.resourceEncoderRegistry = new ResourceEncoderRegistry();
        this.dataRewinderRegistry = new DataRewinderRegistry();
        this.transcoderRegistry = new TranscoderRegistry();
        this.imageHeaderParserRegistry = new ImageHeaderParserRegistry();
        setResourceDecoderBucketPriorityList(
                Arrays.asList(BUCKET_GIF, BUCKET_BITMAP, BUCKET_BITMAP_DRAWABLE));
    }
    / / API to spare
}
Copy the code

Resource Model loader

ModelLoaderRegistry is used to register resource Model loading mode information. For example, a resource defines Model as a Uri class, registers a ModelLoaderFactory, produces the corresponding ModelLoader, and loads the Uri media entity as an InputStream or other form of content

Related categories:

  • ModelLoaderFactory
  • ModelLoader

The encoder

EncoderRegistry is used to register content encode mode information. For example, if a media entity has been loaded as an InputStream, register a corresponding Encoder

for processing encode of content, such as writing to disk

Related classes: Encoder interface and its implementation classes

Accordingly, resourceEncoderRegistry is used to register encode methods for resources. These Encoders-oriented resources, compared to low-level encoded content encapsulation such as InputStream, The Resource implementation class encapsulates encoded content at a higher level.

Related categories:

  • ResourceEncoderInterface and its implementation classes
  • ResourceInterface and its implementation classes
  • EncodeStrategy

It is easy to understand that there are different levels of data encapsulation for media resources:

  • InputSteam to read data
  • Bitmap, BitmapDrawable

Therefore, the encode process has different processing for different levels of encapsulated classes. Of course, Encoder can use other Encoder extension functions in the form of wrapper, adapter,transfer and so on

decoder

DecoderRegistry is used to register media data decoded as Resource information.

As mentioned earlier, in the modelLoaderRegistry registry information, you get ModelLoaders, which are responsible for loading resource Models as resource content, which exists in low-level forms such as InputStream.

Understandably, this can effectively solve the problem of class explosion.

Brain burst: Assume that the number of Model classes is M, and the output forms after decoding are N

  • Without this approach, a total of M * N decoder classes are required
  • In this way, a total of M + N decoder classes are required

As the hierarchy increases, the gap becomes more pronounced

As a rule of thumb, Glide handles the decode process in Wrapper/delegate mode or bridge mode.

Thinking change: Can a similar approach be used in a project to handle the transformation or packaging of data beans between different levels?

Related categories:

  • ResourceDecoderAnd its implementation classes
  • ResourceAnd its implementation classes

converter

Although literally translated as transcoder, but easy to confuse the concept, according to its function called converter

TranscoderRegistry is used to register converters and their responsible primitive type and conversion type information that converts resources from one form to another. For example: Bitmap -> byte[]

Related categories:

  • ResourceTranscoderAnd its implementation classes
  • ResourceAnd its implementation classes

Header information parser

ImageHeaderParserRegistry used to register information parser header information

Note, some operating systems use file extensions to make it easier to decide how to handle files. But the information about how to encode the actual content of a file is stored in the file header information, also known as:File Sigs,File the magic number

For example, FF D8 stands for Generic JPEG Image file, that is, JPE, JPEG, JPG

Learn more about File Sigs

Related categories:

  • ImageHeaderParserAnd its implementation classes
  • ImageType

Module Responsibility Summary

Through the previous analysis, and access to Glide source code, we can carry out a preliminary summary of module responsibilities.

In the following articles, we will conduct more detailed excavation of specific modules, and the class information summarized here is the breakthrough point.

Given the information gathered so farIs not comprehensiveI’m not going to draw a graph, the information below is alsoIs notVery important, so let’s take it as aProvisional memorandumCan. In the following sections, I will summarize each module in a separate diagram

In the next article, we will delve deeper into the resource Model loading and acquisition process.


Cache and pool

  • MemorySizeCalculator
  • LruBitmapPool
  • BitmapPoolAdapter
  • LruArrayPool
  • LruResourceCache
  • InternalCacheDiskCacheFactory

The resource acquisition

  • RequestManagerRetriever
  • RequestManager
  • RequestBuilder
  • Request
  • DefaultConnectivityMonitorFactory

The core processes

  • Engine

Other information is uncertain. The main process information is as follows:

Resource Model loader

  • ModelLoaderFactory
  • ModelLoader

The encoder

  • EncoderInterface and its implementation classes
  • ResourceEncoderInterface and its implementation classes
  • ResourceInterface and its implementation classes
  • EncodeStrategy

decoder

  • ResourceDecoderAnd its implementation classes
  • ResourceAnd its implementation classes

converter

  • ResourceTranscoderAnd its implementation classes
  • ResourceAnd its implementation classes

Header information parser

  • ImageHeaderParserAnd its implementation classes
  • ImageType

The thread pool

  • GlideExecutor

Glide creation and configuration

GlideBuilder used to create, com bumptech. Glide. The module package is used to customize the content of the module, such as:

  • AppGlideModule
  • LibraryGlideModule

And some of the discarded content, not to repeat

Think danger, think retreat, think change

Maybe some readers have a habit of dragging it to the end, as mentioned earlier, and a lot of the content at the end isThe memoNature, and a future series of articles will build on them, with or without reading

But while we’re at it, think about it. Reading a good framework will not only give you insight into the content of the framework, but will also help you hone your design skills:

  • Concern: Are there any noticeable risks to building Glide instances using GlideBuilder?
  • Concern: is there any danger to Glide singleton implementation again in the project?
  • Thinking change: is there any place in the project that can use Glide’s design idea for reference?