“This is my 8th day of the November Gwen Challenge.The final text challenge in 2021”
Glide process analysis
Speaking of picture loading framework, we are most familiar than Glide, but I do not recommend resume familiar Glide, unless you are familiar with its source code, or involved in the development and maintenance of Glide. However, many small partners for the process of Glide and its source interpretation is always unable to start, this article from the three main line to analyze the Glide process and source code!
First thread
Queue joining process:
RequestManager with = Glide.with(this);
RequestBuilder<Drawable> load = with.load(url);
load.into(iv); // When the into method is called, the request to load the image actually begins
Copy the code
Continue to call
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions);
Copy the code
As you continue tracing, you will find the following code
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);// Where the request is sent
Copy the code
void track(Target
target, Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);// Run the request
}
Copy the code
Continue to follow
Glide also has two queues by this method; Run queues and wait queues;public void runRequest(Request request) {
requests.add(request);// Join the runqueue;
if(! isPaused) { request.begin();// Start executing
} else {
pendingRequests.add(request);// Join the queue}}Copy the code
Second thread
How does the request work?
In the first thread, the request.begin() method is when the request actually starts to be executed; Find the request implementation class, SingleRequest, and find its begin method.
Why is it SingleRequest?
There is a line of code in the requestBuilder. into method of the first main line;
Request request = buildRequest(target, targetListener, options);
Copy the code
Keep following it
BuildRequestRecursive () finds a way to build request;Copy the code
In this method, you can trace to
Request mainRequest = buildThumbnailRequestRecursive()
Copy the code
Continue to follow
Request fullRequest =
obtainRequest(
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight);
Copy the code
The code block above ends up calling the SingleRequest.obtain() method to obtain a SingleRequest object; When request.begin () is called, SingleRequest’s begin method is called. Following the begin method, you’ll find the onSizeReady method;
onSizeReady(overrideWidth, overrideHeight);
Copy the code
The engine.load method is traced in the BEGIN method as follows (only part of the code is extracted) :
// From the active cacheEngineResource<? > active = loadFromActiveResources(key, isMemoryCacheable);if(active ! =null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
// Fetch it from the memory cacheEngineResource<? > cached = loadFromCache(key, isMemoryCacheable);if(cached ! =null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
// Disk cache, disk cache is also IO operation, so also use thread pool; Animation thread poolEngineJob<? > current = jobs.get(key, onlyRetrieveFromCache);if(current ! =null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob); // Specific loading, engineJob is to load management class, decodeJob is to return the image data encoding management class;
Copy the code
When the enginejob.start () method is called, the following code is executed:
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
Copy the code
Continue tracking to find DecodeJob’s run method;
Decodejob.run () continues with runWrapped(); Call getNextGenerator()Copy the code
private DataFetcherGenerator getNextGenerator(a) {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
// The SourceGenerator is not a Cache generator. Design pattern-state patterns are used here; (Please make your own enquiries according to section 2)
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: "+ stage); }}Copy the code
Continue tracing to the startNext method in the SourceGenerator class;
loadData.fetcher.loadData(helper.getPriority(), this);
Copy the code
Find HttpUrlFetcher and loadData. It turns out that Glide is the server accessed through HttpUrlConnection and returns the final stream;
Question? How do I know it’s this class? Why not some other class? I can’t read the code here. What do I do? Guess;
Now that you’re not going to get it from the cache, you’re going to get it from the network; So find specific access to the network; What should I do if I can’t find it?
I’m going to go to the implementation class, there’s an HttpUrlFetcher, so where is it initialized?
Find Where to invoke using Find Lead –> Find HttpGlideUrlLoader;
Now look at where the HttpGlideUrlLoader method is called;
Find it Glide, continue to look up, find a kind of Glide build method, find it Glide. Get (context); methods
The third thread
How are queues maintained? In MainActivity we call the following code:
RequestManager with = Glide.with(this);
Copy the code
Follow up to
getRetriever(activity).get(activity)// You get a RequestManagerRetriever object, and get the RequestManager by calling the Get method in the RequestManagerRetriever
Copy the code
To continue down
androidx.fragment.app.FragmentManager fm = activity.getSupportFragmentManager();
return this.supportFragmentGet(activity, fm, (Fragment)null);
Copy the code
Through this. SupportFragmentGet method (the following code), in the end we get SupportRequestManagerFragment object;
private RequestManager supportFragmentGet(@NonNull Context context, @NonNull androidx.fragment.app.FragmentManager fm, @Nullable Fragment parentHint) {
SupportRequestManagerFragment current = this.getSupportRequestManagerFragment(fm, parentHint);// The internal Fragment of this code gets a Fragment if it can, and a new Fragment if it can't. There is no UI processing in this Fragment;
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager = this.factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
Copy the code
After obtaining the Fragment object, assign a value to the RequestManager object. If the RequestManager object is empty, it will help create the Fragment.
The RequestManager object is an important part of lifecycle management because it implements the LifecycleListener interface and sets this interface to itself when creating the RequestManager. This means that Glide creates a UI-less fragment that is bound to the RequestManager; When the user’s activity or fragment is invoked, the system automatically invokes the fragment lifecycle method. The LifecycleListener method is called back to the RequestManager, which has a lifecycle;
When RequestManager onStart method is called, through a series of calls, will be running requests all release, access;
When the onStop method is called, it retrieves data from the running queue, pauses if the current request is running, and adds all data from the running queue to the wait queue.
When the onDestory method is called, all data in the run queue and wait queue is cleared; Then remove the listener; Unbind requestManager from Glide;
Three things to watch ❤️
If you find this article helpful, I’d like to invite you to do three small favors for me:
- Like, forward, have your “like and comment”, is the motivation of my creation.
- Follow the public account “Xiaoxinchat Android” and share original knowledge from time to time
- Also look forward to the follow-up article ing🚀