entrance
The first part summarizes the life cycle management of Glide by using fm and an empty Fragment. Here we continue to see load & into. Don't talk about it
// The first part analyzes with and continues to see load & into
Glide.with(this).load("url").into(...);
- 1.1 load
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
// Instance a RequestBuilder
public <ResourceType> RequestBuilder<ResourceType> as(Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass);
}
// requestManager in RequestBuilder construction
protected RequestBuilder(Glide glide, RequestManager requestManager,
Class<TranscodeType> transcodeClass) {
this.glide = glide;
this.requestManager = requestManager;
this.context = glide.getGlideContext();
this.transcodeClass = transcodeClass;
this.defaultRequestOptions = requestManager.getDefaultRequestOptions();
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.requestOptions = defaultRequestOptions;
}
- 2.1 into
public Target<TranscodeType> into(ImageView view) {
// Main thread verification (involving View refresh)
Util.assertMainThread();
// View non empty verification
Preconditions.checkNotNull(view);
RequestOptions requestOptions = this.requestOptions;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// Get picture location type
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
return into(context.buildImageViewTarget(view, transcodeClass), requestOptions);
}
// Continue to see into
private <Y extends Target<TranscodeType>> Y into(@NonNull Y target, RequestOptions options) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
options = options.autoClone();
// build a Request according to the attribute in target & Options
Request request = buildRequest(target, options);
// target is bound to Request. The previous Request is reused here
Request previous = target.getRequest();
// Here, check whether the request is consistent with previous
//Recycle the request uniformly
if (request.isEquivalentTo(previous)) {
request.recycle();
//Here is to verify the previous execution.
//begin internal mechanism:
//If it is running, it will ensure no interruption
//Restart and submit if complete
//If it fails, start again
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
// If the two requests are inconsistent, delete the old one, update the tartget in the request manager, and request SR to set
requestManager.clear(target);
target.setRequest(request);
// requestManager add request to RequestTracker set < request >
requestManager.track(target, request);
return target;
}
- 2.2 it is not hard to see that the new request is added to the RequestTracker through the requestManager, which maintains a RequestTracker and can handle all requests according to the life cycle
// In the lifecycle callback, the corresponding targetTracker is processed differently
@Override
public void onStart() {
resumeRequests();
targetTracker.onStart();
}
@Override
public void onStop() {
pauseRequests();
targetTracker.onStop();
}
@Override
public void onDestroy() {
targetTracker.onDestroy();
for (Target<?> target : targetTracker.getAll()) {
clear(target);
}
targetTracker.clear();
requestTracker.clearRequests();
lifecycle.removeListener(this);
lifecycle.removeListener(connectivityMonitor);
mainHandler.removeCallbacks(addSelfToLifecycle);
glide.unregisterRequestManager(this);
}
- 3.1 in RequestManager, requestTracker is created and initialized as a member variable of RequestManager. All requests are added to requestTracker by RequestManager for management and are linked with life cycle. Take a look at requestTracker
package com.bumptech.glide.manager;
import com.bumptech.glide.request.Request;
import com.bumptech.glide.util.Util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
public class RequestTracker {
// Use set to prevent GC from killing before starting or onPause
private final Set<Request> requests =
Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final List<Request> pendingRequests = new ArrayList<>();
private boolean isPaused;
/**
* Starts tracking the given request.
*/
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
// Visible for testing.
void addRequest(Request request) {
requests.add(request);
}
/**
* Stops tracking the given request, clears, and recycles it, and returns {@code true} if the
* request was removed or {@code false} if the request was not found.
*/
public boolean clearRemoveAndRecycle(Request request) {
if (request == null) {
return false;
}
boolean isOwnedByUs = requests.remove(request);
// Avoid short circuiting.
isOwnedByUs = pendingRequests.remove(request) || isOwnedByUs;
if (isOwnedByUs) {
request.clear();
request.recycle();
}
return isOwnedByUs;
}
/**
* Returns {@code true} if requests are currently paused, and {@code false} otherwise.
*/
public boolean isPaused() {
return isPaused;
}
/**
* Stops any in progress requests.
*/
public void pauseRequests() {
isPaused = true;
for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning()) {
request.pause();
pendingRequests.add(request);
}
}
}
/**
* Starts any not yet completed or failed requests.
*/
public void resumeRequests() {
isPaused = false;
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isCancelled() && !request.isRunning()) {
request.begin();
}
}
pendingRequests.clear();
}
/**
* Cancels all requests and clears their resources.
*
* <p>After this call requests cannot be restarted.
*/
public void clearRequests() {
for (Request request : Util.getSnapshot(requests)) {
clearRemoveAndRecycle(request);
}
pendingRequests.clear();
}
/**
* Restarts failed requests and cancels and restarts in progress requests.
*/
public void restartRequests() {
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isCancelled()) {
// Ensure the request will be restarted in onResume.
request.pause();
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
}
}
@Override
public String toString() {
return super.toString() + "{numRequests=" + requests.size() + ", isPaused=" + isPaused + "}";
}
}
-
3.2 as can be seen above, RequestTracker maintains the corresponding life cycle of all Requst
- For example, when onPause, pause all requests and add set
- When onResume, restart all requests
- clear all Request when onStop
A wave of 666
summary
- It is mainly used for queue maintenance of all requests and corresponding optimization in life cycle callback
- It's more direct to look at the picture