Recently, due to the function expansion and optimization of the picture library of the project, I spent some time to study Glide, and output a total of 6 analytic articles: Picture frame – Glide custom configuration and components and Registry mechanism picture frame – Glide load WEBP GIF process analysis picture frame – Glide decode WEBP GIF analysis picture frame – Glide cache mechanism parsing picture framework – Research on Glide disk cache

This article on the whole Glide source code macro analysis to do a simple summary. Since the project is based on Glide4.8.0, the source code for analysis is also 4.8.0 for convenience. For the convenience of reading, the article will try not to paste the corresponding code, Glide code quantity is indeed a bit much, want to know more details can refer to the above 6 articles, there are detailed source code analysis.

1. Glide overall structure

1.1 Whole Glide trunk function:

1.2 Overall execution process of image loading:

Glide, as an entry function called externally, mainly collects the request parameters, builds a picture request, and sends it to Engine to obtain the image resource. Engine obtains the image resource from memory first, if there is any active resource directly, if there is no attempt to obtain the image resource from lruCache, if there is no EngineJob thread pool. Launch an asynchronous task called DecodeJob for disk and network fetching. The disk caching strategy is set according to DiskCacheStrategy, which mainly configures image raw data stream caching and resource caching after decoding and transcoding. Generator is a specific image resource acquisition management class, which is finally handed over to the corresponding Fetcher class to handle the task of image resource acquisition through the hierarchy of modelLoader-loadData-specific Fetcher class calls. After successfully obtaining resources, layers of callback back to DecodeJob to do decoding work (if it is the original resource), decoding through modelLoader-loadpath – specific Decoder layers of internal class call relationship finally handed to the corresponding Decoder to do picture resource decoding task. The next step is to set the image to the target control. Here, DecodeJob itself schedules different task types through Stage. In addition, network I/O and local I/O belong to different decodeJobs, that is, the conversion of the two tasks needs to be completed by EngineJob cutting thread. Finally, Registry supports user-defined configurations and components.

1.3 Data conversion process in picture loading

Glide Core class diagram

Here is a brief example of the relationship between some core classes:

  • Glide: Entry class.
  • RequestBuilderRequestManager: Collects parameters, builds Request and Target to be handled by RequestManager.
  • RequestManagerTargetTracker is responsible for binding Target to the page lifecycle and RequestTracker is responsible for initiating the Request.
  • Engine: Load the engine.
  • EngineJob: Thread pool.
  • DcodeJob: asynchronous task, responsible for image acquisition and decoding.
  • Generator: is responsible for obtaining image resources, which are divided into three types (ResourceCache corresponds to the decoded cache, DataCache corresponds to the original ResourceCache, and Source corresponds to the network request). The ModelLoader finally matches the corresponding Fetcher to perform the specific task of obtaining image resources.
  • Target: Displays the target control of the picture.

Iii. Relevant execution process

Glide.with(this).load(URL).into(imageView

3.1.1 with

With does two things:

  • Image loading binding corresponds to page life cycle; There are two types of life cycles: Application and non-application. Respectively by ApplicationLifecycle, ActivityFragmentLifecycle management life cycle.

  • Initialize RequestManager;

3.1.2 the load

Load does one thing:

  • Initialize the RequestBuilder with the RequestManager. Collect model and requestOption parameters to prepare for the subsequent into encapsulation of the request.
3.1.3 into

Into does three main things:

  • Encapsulate and initiate a request.
  • Request Obtains image data.
  • Display the image on the View.

3.2 Glide overall cache mechanism

3.2.1 Memory Data Loading Logic

3.2.2 Overall access logic of memory, disk and network requests

Here is a brief summary:

Fetch logic: Memory > Disk > Network request

  • Memory:

Last loaded resource (activeResources) > (last loaded resource)lruCache.

  • Disk:

If DiskCacheStrategy is actively set, press set. If diskCacheStrategy. ALL: indicates the original resource (ResourceCache) > (DataCache) after conversion

  • Network request:

Request to obtain the image resource flow through the network.

Logical:

  • Memory:

The currently loaded image resource is stored in activeResources. The next time the loading resource is switched, the current activeResources is removed and transferred to lruCache.

  • Disk:

After the network request is successful, the funding source stream is retrieved and then DiskCacheStrategy supports disk caching. If so, the resource is cached via cacheData in SourceGenerator via a callback.

3.3 Glide Disk Cache Process

The disk caching process triggered by the onDataReady callback after a successful network request:There are two key nodes: raw data stream cache and decoded resource cache. The SourceGenerator itself, in addition to making network requests, will also cache the raw data on disk when the network request is successful, as permitted by DiskCacheStrategy, and after DecodeJob decodes the data successfully, Disk caching of decoded resources as permitted by DiskCacheStrategy.

Here is a question: if after the success of the network request cache image raw data stream itself has a problem, decode fails, the best framework is not cached resources after decoding, but to have a problem don’t do processing of raw data cache, this will lead to subsequent access to images by priority preferential access to have a problem of the original data caching, lead to problems.

Solution analysis: Client level: First of all, the client can not independently determine whether it is a decoding failure, because Glide network request failure, decoding failure, IO failure and so on are unified throw onLoadFailed, secondly, the API exposed to the external does not separate clean a picture, only batch clean disk cache, can be batch clean, but this will affect the overall performance. It is also possible to add signature to the DiskCacheStrategy to avoid caching raw data.

Solution: I don’t like using gradle libraries directly. It’s not easy to expand functionality and fix problems. If open source, I usually import the source code, so here I just changed the source code:

DecodeJob.java

private void decodeFromRetrievedData() { if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Retrieved data", startFetchTime, "data: " + currentData + ", cache key: " + currentSourceKey + ", fetcher: " + currentFetcher); } Resource<R> resource = null; try { resource = decodeFromData(currentFetcher, currentData, currentDataSource); } catch (GlideException e) { e.setLoggingDetails(currentAttemptingKey, currentDataSource); throwables.add(e); } if (resource ! = null) { notifyEncodeAndRelease(resource, currentDataSource); } else {/ / decoding failure, delete the cache disk before the original data file diskCacheProvider. GetDiskCache (), delete (new DataCacheKey (currentSourceKey, signature)); runGenerators(); }}Copy the code

Specific analysis process reference article: Picture frame – Glide disk cache research

Well, after the above illustrated analysis, Glide should have a more intuitive understanding of the whole or part of it.

Fourth, Glide compile time annotation +APT application

Finally, a brief introduction to the application of compile time annotation +APT in Glide.

There are two main scenarios for annotation gameplay: run-time and compile-time.

  • Runtime: mainly annotation + reflection, annotation provides labels, reflection to annotation class to do logic.
  • Compile-time: Annotation +APT+ reflection, here APT(Annotation Processor Tool) Annotation Processor, compile-time will generate classes dynamically, and the class contents can be manually assembled or assembled by using tools packaged by JavaPoet.

Glide, on the other hand, when the singleton call get() is initialized:

private static GeneratedAppGlideModule getAnnotationGeneratedGlideModules(Context context) {
  GeneratedAppGlideModule result = null;
  try {
    Class<GeneratedAppGlideModule> clazz =
        (Class<GeneratedAppGlideModule>)
            Class.forName("com.bumptech.glide.GeneratedAppGlideModuleImpl");
   result =
        clazz.getDeclaredConstructor(Context.class).newInstance(context.getApplicationContext());
  } catch (ClassNotFoundException e) {
  ... 
 }
  return result;
}
Copy the code

The com here. Bumptech. Glide. GeneratedAppGlideModuleImpl is APT dynamically generated:

The Processor path corresponding to the source code:

Here is not detailed analysis GeneratedAppGlideModuleImpl generated, it is the final function on the manifest and annotations two registered way to call its applyOptions and registerComponents to trigger custom configurations and components.

Demo address: github.com/Zhto0/Glide…

Well write so much, Glide in general or more complex, this article is Glide to do a macro analysis, as well as the work involved in part of the function of the analysis. On the basis of this macro understanding, it should be able to provide some help to the localization and analysis of the local problems of Glide framework. Of course, if there is any wrong place in the article, welcome criticism and correction!