Personal blog portal
1. Process diagram
Note:
- A Fragment/Activity generates a RequestManager
- Each Application corresponds to an applicationManager, which is a globally unique RequestManager
- Every RequestManager will have a Lifecycle and a RequestTracker
- Each RequestTracker has a List< Request >
- If it is the main thread, register to create an unbounded Fragment to add to the Fragment/Activity and rely on that Fragment to listen for its life cycle
- If it is not the main thread, an application-level Lifecycle is created to simulate the Lifecycle
- The Fragment created in 1. Can feed back the memory and interface life cycle, which completes the memory and interface listening
- You can use the Fragment to determine whether to monitor the network state (if the interface is missing, there is no need to monitor network state)
Second, source code analysis
Life cycle creation
Glide’s five with methods all end up matching the five get() in the RequestManagerRetrieverThe five gets () in the RequestManagerRetriever end up matching the three methods in the RequestManagerRetriever
- When the main thread: get (activity. GetApplicationContext ())
- When the main thread + Activity: fragmentGet (Activity, the Activity getFragmentManager ())
- When the main thread + fragments: supportFragmentGet (fragments. GetActivity (), fragments. GetChildFragmentManager ())
Let’s start with the simpler, non-mainline case
// RequestManagerRetriever
public RequestManager get(Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if(Util.isOnMainThread() && ! (contextinstanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
returnget(((ContextWrapper) context).getBaseContext()); }}// Finally get here
return getApplicationManager(context);
}
private RequestManager getApplicationManager(Context context) {
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
applicationManager = new RequestManager(
context.getApplicationContext(),
new ApplicationLifecycle(),
newEmptyRequestManagerTreeNode()); }}}// applicationManager is globally unique
return applicationManager;
}
// ApplicationLifecycle
class ApplicationLifecycle implements Lifecycle {
@Override
public void addListener(LifecycleListener listener) {
// A false life cycle is simulated here, only startlistener.onStart(); }}Copy the code
Summary:
- Create an ApplicationLifecycle (mock/global lifecycle)
- Into a globally unique applicationManager (RequestManager instance)
Main thread + Activity
// RequestManagerRetriever
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
// This is where the blank Fragment is generatedRequestManagerFragment current = getRequestManagerFragment(fm); . requestManager =new RequestManager(context,
// This is where the lifecycle is createdcurrent.getLifecycle(), current.getRequestManagerTreeNode()); current.setRequestManager(requestManager); .return requestManager;
}
RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
// a series of blank fragments that verify whether the current interface is bound to Glide
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
// Create a new one
current = newRequestManagerFragment(); pendingRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current,FRAGMENT_TAG) .commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); }}return current;
}
// RequestManagerFragment
ActivityFragmentLifecycle getLifecycle(a) {
// It is created in the constructor
return lifecycle;
}
public RequestManagerFragment(a) {
/ / in the end created a ActivityFragmentLifecycle instance, let's see how it works
this(new ActivityFragmentLifecycle());
}
RequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
@Override
public void onStart(a) {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop(a) {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy(a) {
super.onDestroy();
lifecycle.onDestroy();
}
// ActivityFragmentLifecycle
void onStart(a) {
isStarted = true;
for(LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStart(); }}void onStop(a) {
isStarted = false;
for(LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStop(); }}void onDestroy(a) {
isDestroyed = true;
for(LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onDestroy(); }}Copy the code
Very simple,
- Insert a RequestManagerFragment into the Activity with no interface
- Create a ActivityFragmentLifecycle instance, in the function is called called RequestManagerFragment life cycle
Main thread + Fragment
We don’t watch it. It’s the same
- To insert a no interface SupportRequestManagerFragment fragments
- Create a ActivityFragmentLifecycle instance, in the function is called called SupportRequestManagerFragment life cycle
Memory monitoring
- In SupportRequestManagerFragment onLowMemory ()
- OnTrimMemory ()/onLowMemory() in RequestManagerFragment
// SupportRequestManagerFragment
@Override
public void onLowMemory(a) {... requestManager.onLowMemory(); }// RequestManagerFragment
@Override
public void onTrimMemory(int level) {... requestManager.onTrimMemory(level); }@Override
public void onLowMemory(a) {... requestManager.onLowMemory(); }// What is requestManager? Remember the code created by the RequestManagerFragment?
// RequestManagerRetriever
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) { RequestManagerFragment current = getRequestManagerFragment(fm); . requestManager =new RequestManager(context,
current.getLifecycle(),
current.getRequestManagerTreeNode());
// Here here herecurrent.setRequestManager(requestManager); .return requestManager;
}
// RequestManager
public void onTrimMemory(int level) {
glide.trimMemory(level);
}
public void onLowMemory(a) {
glide.clearMemory();
}
/ / Glide singleton
public void clearMemory(a) {... memoryCache.clearMemory(); bitmapPool.clearMemory(); }public void trimMemory(int level) {... memoryCache.trimMemory(level); bitmapPool.trimMemory(level); }Copy the code
Summary:
- Blank Fragment returns to Glide when storage becomes tight
- MemoryCache clears the memoryCache
- BitmapPool clears the memory cache
MemoryCache is an easy-to-guess Glide used for memory caching; So what is a bitmapPool? Android Glide 3.7.0 source code parsing (four), BitmapPool function and principle
- In Android, the image display entity is a Bitmap object. Each image display will first build the image resource into a Bitmap object, and the process of creating and destroying Bitmap consumes system resources, and in serious cases, it will cause frequent GC and interface lag
- An example would be a list of avatars, 10 avatars per page, assuming the GC threshold is 10 images
Normal solution: create 10 bitmaps and release them, create another 10 bitmaps to display the next page, so that no slide is triggered a GC Glide solution: Create a BitmapPool according to the thread pool understanding, create 10 bitmaps do not free, the next 10 images, borrow the memory space of the existing bitmap, no matter how many pages slide, will not trigger GC
Request Task Listening
Take a look at the constructor of the RequestManager
// 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;
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(a) {
lifecycle.addListener(RequestManager.this); }}); }else {
// Register the RequestManager itself into lifecycle
lifecycle.addListener(this);
}
// Here is the network state lifecycle registration, which is covered in the next section
lifecycle.addListener(connectivityMonitor);
}
// LifecycleListener implementation of RequestManager
@Override
public void onStart(a) {
// onStart might not be called because this object may be created after the fragment/activity's onStart method.
resumeRequests();
}
public void resumeRequests(a) {
Util.assertMainThread();
requestTracker.resumeRequests();
}
/** * Lifecycle callback that unregisters for connectivity events (if the android.permission.ACCESS_NETWORK_STATE * permission is present) and pauses in progress loads. */
@Override
public void onStop(a) {
pauseRequests();
}
public void pauseRequests(a) {
Util.assertMainThread();
requestTracker.pauseRequests();
}
/** * Lifecycle callback that cancels all in progress requests and clears and recycles resources for all completed * requests. */
@Override
public void onDestroy(a) {
requestTracker.clearRequests();
}
Copy the code
- The RequestManager registers itself into Lifecycle at the time of initialization
- And by RequestManager LifecycleListener implementation, eventually is called RequestManager. RequestTracker to implement the function
Now let’s track the requestTracker
// RequestManager
public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
// This is a new object
this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
}
// RequestTracker
// LifecycleListener.onStart
public void resumeRequests(a) {
isPaused = false;
for (Request request : Util.getSnapshot(requests)) {
if(! request.isComplete() && ! request.isCancelled() && ! request.isRunning()) { request.begin(); } } pendingRequests.clear(); }// LifecycleListener.onStop
public void pauseRequests(a) {
isPaused = true;
for (Request request : Util.getSnapshot(requests)) {
if(request.isRunning()) { request.pause(); pendingRequests.add(request); }}}// LifecycleListener.onDestroy
public void clearRequests(a) {
for (Request request : Util.getSnapshot(requests)) {
request.clear();
}
pendingRequests.clear();
}
Copy the code
- As you can see, the final call is Request(real) begin(), pause(), clear()
- Request(real) is a GenericRequest object (Android Glide 3.7.0).
Keep tracking GenericRequest
// GenericRequest
// LifecycleListener.onStart
public void begin(a) {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// Call this method to start a new download task
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if(! isComplete() && ! isFailed() && canNotifyStatusChanged()) { target.onLoadStarted(getPlaceholderDrawable()); }if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in "+ LogTime.getElapsedMillis(startTime)); }}// LifecycleListener.onStop
public void pause(a) {
// It looks like onStop and onDestroy are the same logic called
clear();
status = Status.PAUSED;
}
// LifecycleListener.onDestroy
public void clear(a) {
Util.assertMainThread();
if (status == Status.CLEARED) {
return;
}
// Stop tasks are controlled on this side
cancel();
// Resource must be released before canNotifyStatusChanged is called.
if(resource ! =null) {
// This is the release of some resources
releaseResource(resource);
}
if (canNotifyStatusChanged()) {
target.onLoadCleared(getPlaceholderDrawable());
}
// Must be after cancel().
status = Status.CLEARED;
}
void cancel(a) {
status = Status.CANCELLED;
if(loadStatus ! =null) {
loadStatus.cancel();
loadStatus = null; }}// LoadStatus
public static class LoadStatus {
private final EngineJob engineJob;
private final ResourceCallback cb;
public LoadStatus(ResourceCallback cb, EngineJob engineJob) {
this.cb = cb;
this.engineJob = engineJob;
}
public void cancel(a) {
// the EngineJob is called to cancel the taskengineJob.removeCallback(cb); }}Copy the code
- The lifecycle method onStart() finally initiates a Request through begin() of the Request
- OnStop () and onDestroy() are implemented using removeCallback() of the EngineJob
- This EngineJob manages the scheduling of the Request thread when it is downloaded.
Keep tracking EngineJob to see
// EngineJob
public void removeCallback(ResourceCallback cb) {
Util.assertMainThread();
if (hasResource || hasException) {
addIgnoredCallback(cb);
} else {
// Remove the listening callback first
cbs.remove(cb);
if (cbs.isEmpty()) {
// See what it does after it's all removedcancel(); }}}void cancel(a) {
if (hasException || hasResource || isCancelled) {
return;
}
engineRunnable.cancel();
Future currentFuture = future;
if(currentFuture ! =null) {
// The future here is an executorService. submit returns the final destination to terminate the task
currentFuture.cancel(true);
}
isCancelled = true;
listener.onEngineJobCancelled(this, key);
}
Copy the code
Description:
- Glide singleton, when instantiated, creates a diskCacheService (ExecutorService type) and an Engine object, and encapsulates diskCacheService into the Engine
- Call engine.load () to perform a Request(real) task
- Engine.load() creates an EngineJob instance and passes diskCacheService into it
- Enginejob.start () to start a task, which is actually called diskCacheService. Submit ()
- So, cancel() above is actually future.cancel ()
6. Each Request(real) corresponds to one EngineJob instance
There’s only one more thing left to watch, the network status change monitor
Monitoring network status changes
Remember the constructor of the RequestManager?
// 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;
this.glide = Glide.get(context);
this.optionsApplier = new OptionsApplier();
ConnectivityMonitor connectivityMonitor = factory.build(context,
new RequestManagerConnectivityListener(requestTracker));
// If we're the application level request manager, we may be created on a background thread. In that case we
// cannot risk synchronously pausing or resuming requests, so we hack around the issue by delaying adding
// ourselves as a lifecycle listener by posting to the main thread. This should be entirely safe.
if (Util.isOnBackgroundThread()) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run(a) {
lifecycle.addListener(RequestManager.this); }}); }else {
lifecycle.addListener(this);
}
// This is where a connectivityMonitor instance is created and a listener is registered
lifecycle.addListener(connectivityMonitor);
}
/ / DefaultConnectivityMonitor ConnectivityMonitor subclasses
@Override
public void onStart(a) {
register();
}
@Override
public void onStop(a) {
unregister();
}
private void register(a) {
if (isRegistered) {
return;
}
isConnected = isConnected(context);
context.registerReceiver(connectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
isRegistered = true;
}
private void unregister(a) {
if(! isRegistered) {return;
}
context.unregisterReceiver(connectivityReceiver);
isRegistered = false;
}
Copy the code
Very simple, is the interface alive to monitor the network state change, interface destruction, unregistered to monitor the network state change