当前位置: 首页 > news >正文

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 加载图片时,缓存查找顺序如下:

  1. 活动资源缓存(Active Resources)
  2. LRU 内存缓存(LRU Memory Cache)
  3. 转换后图片缓存(Disk Cache Transformed)
  4. 原始图片缓存(Disk Cache Original)
  5. 网络或本地文件系统

在 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 实例负责创建或获取 RequestManagerRequestManager 是 Glide 中管理图片请求的核心类,它能根据 Activity 或 Fragment 的生命周期来控制图片请求的启动、暂停和取消。

2. RequestManagerRetriever 的作用

RequestManagerRetriever 的主要职责是为传入的 Activity 或 Fragment 创建或获取对应的 RequestManager。它通过添加一个隐藏的 FragmentSupportRequestManagerFragment)来监听 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() 方法取消所有图片请求并释放资源。

相关文章:

  • 【特殊场景应对8】LinkedIn式动态简历的利弊分析:在变革与风险间走钢丝
  • A Comprehensive Survey of Spoken Language Models
  • [自记录]一次Nvidia显卡的AI容器基础镜像制作过程(含Torch版本和ONNXRuntime版本选择)
  • 【阿里云大模型高级工程师ACP习题集】2.5 优化RAG应用提升问答准确度(⭐️⭐️⭐️ 重点章节!!!)
  • 全栈开发的未来:低代码与AI辅助编程的边界探索
  • Python爬虫(4)CSS核心机制:全面解析选择器分类、用法与实战应用
  • 遥感金融风险监管:技术革新与实践探索
  • 不同ECU(MCU/ZCU/CCU)其部署(实现)的功能存在差异
  • 别让算力掉队:AI架构里被忽视的关键一环
  • 测试基础笔记第十二天
  • 安全性测试常规测试点全解析:从基础到高级的实战指南
  • 代理ip和实际ip的区别和联系
  • 一款好用的桌面待办工具,轻松掌控时间沙漏!
  • AiFlutter 低代码平台介绍
  • Linux软硬链接和动静态库(20)
  • 一文带你掌握java的stream流
  • ADVB协议同步
  • 【c++11】c++11新特性(下)(可变参数模板、default和delete、容器新设定、包装器)
  • 学习AI必知的20大概念
  • Gemini 2.5 Pro代码实测:它能抢程序员饭碗了吗?
  • 凝聚多方力量,中国农科院油菜产业专家团部署单产提升新任务
  • 我国首次实现地月距离尺度的卫星激光测距
  • 国新办发布会丨2024年市监部门查办知产领域侵权行政违法案件4.4万件
  • 讲座预告|大国博弈与创新破局:如何激励中国企业创新
  • 深圳大学传播学院院长巢乃鹏已任深圳大学副校长
  • 出发!陈冬、陈中瑞、王杰三名航天员领命出征