Analysis of Glide Lifecycle Management in Android
The article dissects Glide’s lifecycle management by tracing how Glide.with creates a singleton RequestManager via RequestManagerRetriever, caches headless RequestManagerFragments, forwards Activity/Fragment callbacks through ActivityFragmentLifecycle to pause, resume, or clear image requests, monitors network changes with a ConnectivityMonitor, and responds to memory pressure via component callbacks, thereby integrating Android component lifecycles, connectivity, and memory management into its image‑loading engine.
Android image loading is a fundamental feature, and Glide is the officially recommended library. This article focuses on the source‑code analysis of Glide's lifecycle management rather than simple usage.
1. Overview
The article continues from the previous analysis of Glide's cache flow and aims to answer four questions: how Glide implements page lifecycle, why it caches Fragments, how it monitors network changes, and how it monitors memory.
2. Glide lifecycle propagation
The entry point is Glide.with(Activity) , which creates a singleton Glide instance and obtains a RequestManager via RequestManagerRetriever . The relevant code is:
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
Preconditions.checkNotNull(context, "You cannot start a load on a not yet attached View or a Fragment where getActivity() returns null");
return Glide.get(context).getRequestManagerRetriever();
}
@NonNull
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) {
if (isInitializing) {
throw new IllegalStateException("You cannot call Glide.get() in registerComponents(), use the provided Glide instance instead");
}
isInitializing = true;
initializeGlide(context);
isInitializing = false;
}When with() receives a non‑Activity (e.g., a Fragment), Glide still creates a headless RequestManagerFragment to manage the lifecycle.
3. RequestManagerRetriever and Fragment caching
The retriever first looks for an existing RequestManagerFragment in the Activity's FragmentManager . If none is found, it checks a temporary cache pendingRequestManagerFragments . If still absent, it creates a new fragment, adds it to the cache, and commits the transaction:
private RequestManagerFragment getRequestManagerFragment(@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}The temporary cache prevents creating duplicate fragments when multiple image requests are issued from the same Activity.
4. RequestManagerFragment and ActivityFragmentLifecycle
RequestManagerFragment holds a RequestManager and an ActivityFragmentLifecycle . Its lifecycle callbacks forward to the ActivityFragmentLifecycle :
public class RequestManagerFragment extends Fragment {
private final ActivityFragmentLifecycle lifecycle;
@Nullable private RequestManager requestManager;
public RequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
...
}The ActivityFragmentLifecycle maintains a weak set of LifecycleListener s and notifies them on start/stop/destroy:
class ActivityFragmentLifecycle implements Lifecycle {
private final Set
lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap
());
private boolean isStarted;
private boolean isDestroyed;
@Override
public void addListener(@NonNull LifecycleListener listener) {
lifecycleListeners.add(listener);
if (isDestroyed) {
listener.onDestroy();
} else if (isStarted) {
listener.onStart();
} else {
listener.onStop();
}
}
@Override
public void removeListener(@NonNull LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
void onStart() {
isStarted = true;
for (LifecycleListener l : Util.getSnapshot(lifecycleListeners)) {
l.onStart();
}
}
void onStop() {
isStarted = false;
for (LifecycleListener l : Util.getSnapshot(lifecycleListeners)) {
l.onStop();
}
}
void onDestroy() {
isDestroyed = true;
for (LifecycleListener l : Util.getSnapshot(lifecycleListeners)) {
l.onDestroy();
}
}
}The RequestManager registers itself as a LifecycleListener during construction, so it receives these callbacks and starts, stops, or clears requests accordingly.
5. RequestManager lifecycle handling
@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);
}This ensures that image loading stops when the UI is not visible and resources are released when the Activity/Fragment is destroyed.
6. Handler message order illustration
The article also demonstrates how Android's Handler processes posted Runnables and messages in a FIFO manner, showing the exact log output of a mixed post() and sendMessage() sequence.
HandlerRunT: =========Begin!============
HandlerRunT: =========Middle!============
HandlerRunT: =========End!============
HandlerRunT: =========Next Begin!============
HandlerRunT: =========Next Middle!============
HandlerRunT: =========Next End!============
HandlerRunT: =========First!============
HandlerRunT: =========Second!============
HandlerRunT: =========Next First!============
HandlerRunT: =========Next Second!============The logs confirm that UI thread logs appear first, followed by queued Handler messages.
7. Network change monitoring
Glide registers a ConnectivityMonitor as a lifecycle listener. The default implementation checks the ACCESS_NETWORK_STATE permission and creates either DefaultConnectivityMonitor or a no‑op NullConnectivityMonitor :
public ConnectivityMonitor build(@NonNull Context context,
@NonNull ConnectivityMonitor.ConnectivityListener listener) {
int permissionResult = ContextCompat.checkSelfPermission(context, NETWORK_PERMISSION);
boolean hasPermission = permissionResult == PackageManager.PERMISSION_GRANTED;
return hasPermission ? new DefaultConnectivityMonitor(context, listener)
: new NullConnectivityMonitor();
}The DefaultConnectivityMonitor registers a broadcast receiver for CONNECTIVITY_ACTION and notifies the listener when the connectivity state changes, causing RequestManager to restart pending requests.
private final BroadcastReceiver connectivityReceiver = new BroadcastReceiver() {
@Override
public void onReceive(@NonNull Context context, Intent intent) {
boolean wasConnected = isConnected;
isConnected = isConnected(context);
if (wasConnected != isConnected) {
listener.onConnectivityChanged(isConnected);
}
}
};
@Override
public void onStart() { register(); }
@Override
public void onStop() { unregister(); }Inside RequestManager the listener simply restarts requests when connectivity is restored:
private static class RequestManagerConnectivityListener implements ConnectivityMonitor.ConnectivityListener {
private final RequestTracker requestTracker;
RequestManagerConnectivityListener(@NonNull RequestTracker requestTracker) {
this.requestTracker = requestTracker;
}
@Override
public void onConnectivityChanged(boolean isConnected) {
if (isConnected) {
requestTracker.restartRequests();
}
}
}8. Memory monitoring
Glide registers itself as a component callback. When the system calls onTrimMemory(int level) , Glide forwards the call to its internal caches (memory cache, bitmap pool, array pool) to release resources based on the memory pressure level:
@Override
public void onTrimMemory(int level) {
trimMemory(level);
}
public void trimMemory(int level) {
Util.assertMainThread();
memoryCache.trimMemory(level);
bitmapPool.trimMemory(level);
arrayPool.trimMemory(level);
}9. Conclusion
The article answered the four initial questions by walking through the relevant source files, showing how Glide ties the Android component lifecycle, network state, and memory pressure to its image‑loading engine. Future posts will continue the deep dive into other parts of Glide.
vivo Internet Technology
Sharing practical vivo Internet technology insights and salon events, plus the latest industry news and hot conferences.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.