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

相关推荐
xq952742 分钟前
Andorid Google 登录接入文档
android
黄林晴2 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab14 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿17 小时前
Android MediaPlayer 笔记
android
Jony_18 小时前
Android 启动优化方案
android
阿巴斯甜18 小时前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇18 小时前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android
_小马快跑_1 天前
Kotlin | 从SparseArray、ArrayMap的set操作符看类型检查的不同
android
_小马快跑_1 天前
Android | 为什么有了ArrayMap还要再设计SparseArray?
android