Android学习总结之Glide篇(缓存和生命周期)

一、Glide缓存

1. 内存缓存

内存缓存主要包含活动资源缓存与 LRU 内存缓存这两个级别。

活动资源缓存(Active Resources)
  • 作用 :用于存放当前正在被显示的图片资源。当某张图片正展示在 ImageView 上时,它会被纳入活动资源缓存,防止重复加载相同图片。
  • 源码分析 :在 Engine 类里,activeResources 是一个 WeakReference 类型的集合,用来存储活动资源。图片加载完成并显示时,Engineactivate 方法会将图片资源存入活动资源缓存:
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(); 
    }
}

当图片不再显示时,Enginedeactivate 方法会将其从活动资源缓存中移除:

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 算法的缓存类。MemoryCacheAdapterput 方法用于将图片资源存入 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 加载图片时,缓存查找顺序如下:

  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 等)的类型进行不同处理。

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

2. RequestManagerRetriever 的作用

RequestManagerRetriever 的主要职责是为传入的 Activity 或 Fragment 创建或获取对应的 RequestManager。它通过添加一个隐藏的 FragmentSupportRequestManagerFragment)来监听 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;
    }
}

SupportRequestManagerFragmentonStart()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() 方法取消所有图片请求并释放资源。

相关推荐
Angindem8 分钟前
SpringClound 微服务分布式Nacos学习笔记
分布式·学习·微服务
QING61830 分钟前
Android 定位权限兼容问题详解 —— 新手指南
android·ai编程·trae
QING61835 分钟前
Android 存储权限兼容问题详解 —— 新手指南
android·ai编程·trae
虾球xz35 分钟前
游戏引擎学习第244天: 完成异步纹理下载
c++·学习·游戏引擎
BOB-wangbaohai36 分钟前
Flowable7.x学习笔记(十四)查看部署流程Bpmn2.0-xml
xml·笔记·学习
先生沉默先1 小时前
c#接口_抽象类_多态学习
开发语言·学习·c#
豆芽8191 小时前
图解YOLO(You Only Look Once)目标检测(v1-v5)
人工智能·深度学习·学习·yolo·目标检测·计算机视觉
逾非时1 小时前
MySQL触法器
android·mysql·sqlserver
友善啊,朋友1 小时前
《普通逻辑》学习记录——性质命题及其推理
学习·逻辑学