Android学习总结之Glide篇(缓存和生命周期)
一、Glide缓存
1. 内存缓存
内存缓存主要包含活动资源缓存与 LRU 内存缓存这两个级别。
活动资源缓存(Active Resources)
- 作用:用于存放当前正在被显示的图片资源。当某张图片正展示在
ImageView
上时,它会被纳入活动资源缓存,防止重复加载相同图片。 - 源码分析:在
Engine
类里,activeResources
是一个WeakReference
类型的集合,用来存储活动资源。图片加载完成并显示时,Engine
的activate
方法会将图片资源存入活动资源缓存:
// Engine.java
// 将图片资源放入活动资源缓存
void activate(Key key, EngineResource<?> resource) {// 确保在主线程执行Util.assertMainThread(); // 创建一个弱引用,指向要存入缓存的图片资源ActiveResources.ResourceWeakReference toPut =new ActiveResources.ResourceWeakReference(key, resource, getReferenceQueue());// 将弱引用存入活动资源缓存集合,若存在相同键的弱引用则返回旧的ActiveResources.ResourceWeakReference removed = activeResources.put(key, toPut); if (removed != null) {// 若有旧的弱引用,重置它removed.reset(); }
}
当图片不再显示时,Engine
的 deactivate
方法会将其从活动资源缓存中移除:
// Engine.java
// 从活动资源缓存中移除图片资源
@Nullable
EngineResource<?> deactivate(Key key) {Util.assertMainThread();// 从活动资源缓存集合中移除指定键的弱引用ActiveResources.ResourceWeakReference removed = activeResources.remove(key); if (removed != null) {// 若移除的弱引用不为空,重置它,并返回对应的图片资源removed.reset(); return removed.getResource();}return null;
}
LRU 内存缓存(LRU Memory Cache)
- 作用:作为内存缓存的第二级,当活动资源缓存中没有所需图片时,会在此查找。LRU 算法会优先剔除最近最少使用的图片,以合理利用缓存空间。
- 源码分析:
MemoryCacheAdapter
类借助LruCache
实现 LRU 内存缓存,LruCache
是 Android 提供的基于 LRU 算法的缓存类。MemoryCacheAdapter
的put
方法用于将图片资源存入 LRU 内存缓存:
// MemoryCacheAdapter.java
// 将图片资源存入 LRU 内存缓存
@Override
public void put(Key key, EngineResource<?> resource) {cache.put(key, resource);
}
get
方法用于从 LRU 内存缓存中获取图片资源:
// MemoryCacheAdapter.java
// 从 LRU 内存缓存中获取图片资源
@Override
@Nullable
public EngineResource<?> get(Key key) {return cache.get(key);
}
2. 磁盘缓存
磁盘缓存分为原始图片缓存和转换后图片缓存两个级别。
原始图片缓存(Disk Cache Original)
- 作用:用于存储从网络或本地文件系统下载的原始图片。当内存缓存中没有图片时,会先检查原始图片缓存。
- 源码分析:
DiskLruCacheWrapper
类实现了磁盘缓存的操作。put
方法用于将原始图片数据写入磁盘缓存:
// DiskLruCacheWrapper.java
// 将原始图片数据写入磁盘缓存
@Override
public void put(Key key, Writer writer) {DiskLruCache.Editor editor = null;try {// 获取用于写入磁盘缓存的编辑器editor = cache.edit(getKeyForDiskCache(key)); if (editor == null) {throw new IllegalStateException("Had two simultaneous puts for: " + key);}// 将图片数据写入缓存,并根据写入结果决定提交或放弃写入if (writer.write(editor.newOutputStream(0))) { editor.commit();} else {abortQuietly(editor);}} catch (IOException e) {// 出现异常时放弃写入abortQuietly(editor); }
}
get
方法用于从磁盘缓存中读取原始图片数据:
// DiskLruCacheWrapper.java
// 从磁盘缓存中读取原始图片数据
@Override
@Nullable
public File get(Key key) {DiskLruCache.Snapshot snapshot = null;try {// 获取磁盘缓存中指定键的快照snapshot = cache.get(getKeyForDiskCache(key)); if (snapshot != null) {// 若快照存在,返回对应的文件return snapshot.getFile(0); }} catch (IOException e) {// 出现异常不做处理} finally {if (snapshot != null) {// 无论是否读取成功,关闭快照snapshot.close(); }}return null;
}
转换后图片缓存(Disk Cache Transformed)
- 作用:用于存储经过 Glide 转换(如裁剪、缩放、模糊等)后的图片。当要显示经过转换的图片时,会先检查此缓存。
- 源码分析:转换后图片缓存的实现和原始图片缓存类似,同样通过
DiskLruCacheWrapper
类操作。不同的是,存储和读取时使用的键会依据图片的转换操作计算,以保证不同转换后的图片能正确缓存和读取。
3. 缓存查找顺序
当使用 Glide 加载图片时,缓存查找顺序如下:
- 活动资源缓存(Active Resources)
- LRU 内存缓存(LRU Memory Cache)
- 转换后图片缓存(Disk Cache Transformed)
- 原始图片缓存(Disk Cache Original)
- 网络或本地文件系统
在 Engine
类的 load
方法中实现了上述查找顺序。先从活动资源缓存找,若没有则找 LRU 内存缓存,接着找转换后图片缓存和原始图片缓存,都没有时才从网络或本地文件系统获取。这种多级缓存机制和特定的查找顺序,能有效提高图片加载效率,减少不必要的资源获取操作,提升应用性能和用户体验
二、Glide的生命周期
1. 生命周期管理的入口
在 Android 应用中使用 Glide 加载图片,常见代码如 Glide.with(this).load(url).into(imageView)
。这里的 Glide.with()
方法是 Glide 生命周期管理的起始点,它会依据传入参数(Activity、Fragment 等)的类型进行不同处理。
// Glide.java
// 根据传入的 Activity 获取 RequestManager
public static RequestManager with(@NonNull Activity activity) {// 调用 getRetriever 方法获取 RequestManagerRetriever 实例,再调用其 get 方法获取 RequestManagerreturn getRetriever(activity).get(activity);
}// 根据传入的 FragmentActivity 获取 RequestManager
public static RequestManager with(@NonNull FragmentActivity activity) {return getRetriever(activity).get(activity);
}// 根据传入的 Fragment 获取 RequestManager
public static RequestManager with(@NonNull Fragment fragment) {// 先通过 fragment.getContext() 获取上下文,再获取 RequestManagerRetriever 实例并调用其 get 方法return getRetriever(fragment.getContext()).get(fragment);
}
getRetriever()
方法返回的 RequestManagerRetriever
实例负责创建或获取 RequestManager
。RequestManager
是 Glide 中管理图片请求的核心类,它能根据 Activity 或 Fragment 的生命周期来控制图片请求的启动、暂停和取消。
2. RequestManagerRetriever 的作用
RequestManagerRetriever
的主要职责是为传入的 Activity 或 Fragment 创建或获取对应的 RequestManager
。它通过添加一个隐藏的 Fragment
(SupportRequestManagerFragment
)来监听 Activity 或 Fragment 的生命周期变化。
// RequestManagerRetriever.java
// 根据传入的 Activity 获取 RequestManager
@NonNull
RequestManager get(@NonNull Activity activity) {// 判断是否在后台线程,若是则使用 Activity 的 ApplicationContext 获取 RequestManagerif (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext());} else {// 检查 Activity 是否已销毁,若已销毁则抛出异常assertNotDestroyed(activity); // 获取 Activity 的 FragmentManagerFragmentManager fm = activity.getFragmentManager(); // 调用 supportFragmentGet 方法获取 RequestManagerreturn supportFragmentGet(activity, fm, null, isActivityVisible(activity)); }
}// 辅助方法,用于获取 RequestManager
@NonNull
private RequestManager supportFragmentGet(@NonNull Context context,@NonNull FragmentManager fm,@Nullable Fragment parentHint,boolean isParentVisible) {// 获取 SupportRequestManagerFragment 实例,若不存在则创建SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint); // 从 SupportRequestManagerFragment 中获取 RequestManagerRequestManager requestManager = current.getRequestManager(); if (requestManager == null) {// 获取 Glide 实例Glide glide = Glide.get(context); // 创建 RequestManager 实例requestManager =factory.build(glide, current.getLifecycle(), current.getRequestManagerTreeNode(), context); // 将创建好的 RequestManager 设置到 SupportRequestManagerFragment 中current.setRequestManager(requestManager); }return requestManager;
}
在 supportFragmentGet()
方法中,先通过 getSupportRequestManagerFragment()
方法获取隐藏的 SupportRequestManagerFragment
。若该 Fragment
不存在,就创建一个新的并添加到 Activity 或 Fragment 中。SupportRequestManagerFragment
会监听 Activity 或 Fragment 的生命周期变化,并把这些变化传递给 RequestManager
。
3. SupportRequestManagerFragment 的生命周期监听
SupportRequestManagerFragment
是一个隐藏的 Fragment,它继承自 Fragment
并实现了 LifecycleOwner
接口。通过实现这个接口,它可以将自身的生命周期事件暴露给 RequestManager
。
// SupportRequestManagerFragment.java
public class SupportRequestManagerFragment extends Fragment {// 持有 ActivityFragmentLifecycle 实例,用于管理和分发生命周期事件private final ActivityFragmentLifecycle lifecycle; // 持有 RequestManager 实例,用于管理图片请求private RequestManager requestManager; public SupportRequestManagerFragment() {// 调用另一个构造方法,传入默认的 ActivityFragmentLifecycle 实例this(new ActivityFragmentLifecycle()); }@VisibleForTestingpublic SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {this.lifecycle = lifecycle;}@Overridepublic void onStart() {super.onStart();// 调用 ActivityFragmentLifecycle 的 onStart 方法,传递生命周期事件lifecycle.onStart(); }@Overridepublic void onStop() {super.onStop();// 调用 ActivityFragmentLifecycle 的 onStop 方法,传递生命周期事件lifecycle.onStop(); }@Overridepublic void onDestroy() {super.onDestroy();// 调用 ActivityFragmentLifecycle 的 onDestroy 方法,传递生命周期事件lifecycle.onDestroy(); }@NonNullpublic Lifecycle getLifecycle() {return lifecycle;}public void setRequestManager(@Nullable RequestManager requestManager) {this.requestManager = requestManager;}@Nullablepublic RequestManager getRequestManager() {return requestManager;}
}
在 SupportRequestManagerFragment
的 onStart()
、onStop()
和 onDestroy()
方法中,会调用 ActivityFragmentLifecycle
的相应方法,把生命周期事件传递给 ActivityFragmentLifecycle
。
4. ActivityFragmentLifecycle 的事件分发
ActivityFragmentLifecycle
实现了 Lifecycle
接口,负责管理和分发生命周期事件。当 SupportRequestManagerFragment
的生命周期发生变化时,ActivityFragmentLifecycle
会将这些变化通知给所有注册的 LifecycleListener
。
// ActivityFragmentLifecycle.java
class ActivityFragmentLifecycle implements Lifecycle {// 使用 Set 集合存储 LifecycleListener,使用 WeakHashMap 避免内存泄漏private final Set<LifecycleListener> lifecycleListeners =Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>()); private boolean isStarted;private boolean isDestroyed;@Overridepublic void addListener(@NonNull LifecycleListener listener) {// 将 LifecycleListener 添加到集合中lifecycleListeners.add(listener); // 根据当前生命周期状态,调用 LifecycleListener 的相应方法if (isDestroyed) { listener.onDestroy();} else if (isStarted) {listener.onStart();} else {listener.onStop();}}@Overridepublic void removeListener(@NonNull LifecycleListener listener) {// 从集合中移除 LifecycleListenerlifecycleListeners.remove(listener); }void onStart() {isStarted = true;// 遍历 LifecycleListener 集合,调用每个 Listener 的 onStart 方法for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStart();}}void onStop() {isStarted = false;// 遍历 LifecycleListener 集合,调用每个 Listener 的 onStop 方法for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStop();}}void onDestroy() {isDestroyed = true;// 遍历 LifecycleListener 集合,调用每个 Listener 的 onDestroy 方法for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onDestroy();}}
}
RequestManager
实现了 LifecycleListener
接口,并注册到 ActivityFragmentLifecycle
中。当 ActivityFragmentLifecycle
接收到生命周期事件时,会调用 RequestManager
的相应方法,进而实现对图片请求的控制。
5. RequestManager 的生命周期响应
RequestManager
实现了 LifecycleListener
接口,会根据接收到的生命周期事件来控制图片请求的状态。
// RequestManager.java
public class RequestManager implements LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {@Overridepublic void onStart() {// 调用 resumeRequests 方法,恢复所有暂停的图片请求resumeRequests(); }@Overridepublic void onStop() {// 调用 pauseRequests 方法,暂停所有正在运行的图片请求pauseRequests(); }@Overridepublic void onDestroy() {// 调用 clearRequests 方法,取消所有图片请求并释放资源clearRequests(); }public void resumeRequests() {isPaused = false;// 遍历 requests 集合,恢复未完成、未取消且未运行的请求for (Request request : Util.getSnapshot(requests)) { if (!request.isComplete() && !request.isCancelled() && !request.isRunning()) {request.begin();}}// 清空 pendingRequests 集合pendingRequests.clear(); }public void pauseRequests() {isPaused = true;// 遍历 requests 集合,暂停正在运行的请求,并将其添加到 pendingRequests 集合for (Request request : Util.getSnapshot(requests)) { if (request.isRunning()) {request.pause();pendingRequests.add(request);}}}public void clearRequests() {// 遍历 requests 集合,清除每个请求for (Request request : Util.getSnapshot(requests)) { request.clear();}// 清空 requests 和 pendingRequests 集合requests.clear(); pendingRequests.clear();}
}
当 RequestManager
接收到 onStart()
事件时,会调用 resumeRequests()
方法恢复所有暂停的图片请求;接收到 onStop()
事件时,调用 pauseRequests()
方法暂停所有正在运行的图片请求;接收到 onDestroy()
事件时,调用 clearRequests()
方法取消所有图片请求并释放资源。