一、Glide缓存
1. 内存缓存
内存缓存主要包含活动资源缓存与 LRU 内存缓存这两个级别。
活动资源缓存(Active Resources)
- 作用 :用于存放当前正在被显示的图片资源。当某张图片正展示在
ImageView
上时,它会被纳入活动资源缓存,防止重复加载相同图片。 - 源码分析 :在
Engine
类里,activeResources
是一个WeakReference
类型的集合,用来存储活动资源。图片加载完成并显示时,Engine
的activate
方法会将图片资源存入活动资源缓存:
java
// 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
方法会将其从活动资源缓存中移除:
java
// 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 内存缓存:
java
// MemoryCacheAdapter.java
// 将图片资源存入 LRU 内存缓存
@Override
public void put(Key key, EngineResource<?> resource) {
cache.put(key, resource);
}
get
方法用于从 LRU 内存缓存中获取图片资源:
java
// MemoryCacheAdapter.java
// 从 LRU 内存缓存中获取图片资源
@Override
@Nullable
public EngineResource<?> get(Key key) {
return cache.get(key);
}
2. 磁盘缓存
磁盘缓存分为原始图片缓存和转换后图片缓存两个级别。
原始图片缓存(Disk Cache Original)
- 作用:用于存储从网络或本地文件系统下载的原始图片。当内存缓存中没有图片时,会先检查原始图片缓存。
- 源码分析 :
DiskLruCacheWrapper
类实现了磁盘缓存的操作。put
方法用于将原始图片数据写入磁盘缓存:
java
// 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
方法用于从磁盘缓存中读取原始图片数据:
java
// 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 等)的类型进行不同处理。
java
// Glide.java
// 根据传入的 Activity 获取 RequestManager
public static RequestManager with(@NonNull Activity activity) {
// 调用 getRetriever 方法获取 RequestManagerRetriever 实例,再调用其 get 方法获取 RequestManager
return 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 的生命周期变化。
java
// RequestManagerRetriever.java
// 根据传入的 Activity 获取 RequestManager
@NonNull
RequestManager get(@NonNull Activity activity) {
// 判断是否在后台线程,若是则使用 Activity 的 ApplicationContext 获取 RequestManager
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
// 检查 Activity 是否已销毁,若已销毁则抛出异常
assertNotDestroyed(activity);
// 获取 Activity 的 FragmentManager
FragmentManager fm = activity.getFragmentManager();
// 调用 supportFragmentGet 方法获取 RequestManager
return 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 中获取 RequestManager
RequestManager 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
。
java
// SupportRequestManagerFragment.java
public class SupportRequestManagerFragment extends Fragment {
// 持有 ActivityFragmentLifecycle 实例,用于管理和分发生命周期事件
private final ActivityFragmentLifecycle lifecycle;
// 持有 RequestManager 实例,用于管理图片请求
private RequestManager requestManager;
public SupportRequestManagerFragment() {
// 调用另一个构造方法,传入默认的 ActivityFragmentLifecycle 实例
this(new ActivityFragmentLifecycle());
}
@VisibleForTesting
public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
@Override
public void onStart() {
super.onStart();
// 调用 ActivityFragmentLifecycle 的 onStart 方法,传递生命周期事件
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
// 调用 ActivityFragmentLifecycle 的 onStop 方法,传递生命周期事件
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
// 调用 ActivityFragmentLifecycle 的 onDestroy 方法,传递生命周期事件
lifecycle.onDestroy();
}
@NonNull
public Lifecycle getLifecycle() {
return lifecycle;
}
public void setRequestManager(@Nullable RequestManager requestManager) {
this.requestManager = requestManager;
}
@Nullable
public RequestManager getRequestManager() {
return requestManager;
}
}
在 SupportRequestManagerFragment
的 onStart()
、onStop()
和 onDestroy()
方法中,会调用 ActivityFragmentLifecycle
的相应方法,把生命周期事件传递给 ActivityFragmentLifecycle
。
4. ActivityFragmentLifecycle 的事件分发
ActivityFragmentLifecycle
实现了 Lifecycle
接口,负责管理和分发生命周期事件。当 SupportRequestManagerFragment
的生命周期发生变化时,ActivityFragmentLifecycle
会将这些变化通知给所有注册的 LifecycleListener
。
java
// 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;
@Override
public void addListener(@NonNull LifecycleListener listener) {
// 将 LifecycleListener 添加到集合中
lifecycleListeners.add(listener);
// 根据当前生命周期状态,调用 LifecycleListener 的相应方法
if (isDestroyed) {
listener.onDestroy();
} else if (isStarted) {
listener.onStart();
} else {
listener.onStop();
}
}
@Override
public void removeListener(@NonNull LifecycleListener listener) {
// 从集合中移除 LifecycleListener
lifecycleListeners.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
接口,会根据接收到的生命周期事件来控制图片请求的状态。
java
// RequestManager.java
public class RequestManager implements LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {
@Override
public void onStart() {
// 调用 resumeRequests 方法,恢复所有暂停的图片请求
resumeRequests();
}
@Override
public void onStop() {
// 调用 pauseRequests 方法,暂停所有正在运行的图片请求
pauseRequests();
}
@Override
public 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()
方法取消所有图片请求并释放资源。