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

面试总结之 Glide自定义的三级缓存策略

一、为什么需要三级缓存?

在移动应用开发中,图片加载性能直接影响用户体验。根据 Google 统计,图片加载延迟超过 1 秒会导致 32% 的用户流失。传统图片加载方案存在以下痛点:

  • 内存占用高:未压缩的大图直接占用大量内存
  • 重复下载:相同图片多次从网络获取
  • 弱网体验差:离线场景无法加载图片

Glide 通过三级缓存策略,将图片加载速度提升 50%,内存占用降低 45%

内存缓存(Memory Cache)

import android.content.Context;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.load.engine.cache.LruResourceCache;
import com.bumptech.glide.module.AppGlideModule;

public class CustomGlideModule extends AppGlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        // 获取设备的最大内存
        int maxMemory = (int) Runtime.getRuntime().maxMemory();
        // 计算内存缓存的大小,这里设置为最大内存的15%
        int memoryCacheSize = maxMemory / 1024 / 1024 * 15;
        // 创建LruResourceCache对象
        builder.setMemoryCache(new LruResourceCache(memoryCacheSize));
    }
}

解释:我们自定义了一个 AppGlideModule 类 CustomGlideModule。在 applyOptions 方法里,先获取设备的最大内存,接着计算出内存缓存的大小,这里设定为最大内存的 15%,最后使用 LruResourceCache 来设置内存缓存。  

  • LruCache 实现:最大缓存容量为应用内存的 15%
  • 缓存键生成策略:包含 URL + 宽高 + 格式的复合键
  • 内存泄漏防护:通过 Glide 生命周期绑定

磁盘缓存(Disk Cache)

import android.content.Context;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory;
import com.bumptech.glide.module.AppGlideModule;

public class CustomDiskCacheGlideModule extends AppGlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        // 设置磁盘缓存的路径
        String diskCachePath = context.getCacheDir().getPath() + "/glide_cache";
        // 设置磁盘缓存的大小为100MB
        int diskCacheSize = 1024 * 1024 * 100;
        // 创建DiskLruCacheFactory对象
        builder.setDiskCache(new DiskLruCacheFactory(diskCachePath, diskCacheSize));
    }
}

解释:我们同样自定义了一个 AppGlideModule 类 CustomDiskCacheGlideModule。在 applyOptions 方法里,先设置磁盘缓存的路径,再将磁盘缓存的大小设置为 100MB,最后使用 DiskLruCacheFactory 来设置磁盘缓存。

  • 磁盘缓存目录:应用专属缓存目录
  • 缓存淘汰算法:LRU 策略
  • 缓存数据格式:使用 Glide 的默认序列化方式

网络缓存(Network Cache)

import android.content.Context;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.AppGlideModule;
import okhttp3.Cache;
import okhttp3.OkHttpClient;

import java.io.InputStream;

public class CustomNetworkCacheGlideModule extends AppGlideModule {
    @Override
    public void registerComponents(Context context, Glide glide, Registry registry) {
        // 设置网络缓存的路径
        Cache cache = new Cache(context.getCacheDir(), 1024 * 1024 * 50);
        // 创建OkHttpClient对象并设置缓存
        OkHttpClient client = new OkHttpClient.Builder()
               .cache(cache)
               .build();
        // 注册OkHttpUrlLoader,让Glide使用OkHttp进行网络请求
        registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(client));
    }
}

   解释:自定义了 CustomNetworkCacheGlideModule 类,在 registerComponents 方法中,先设置网络缓存的路径和大小(这里是 50MB),然后创建 OkHttpClient 并设置缓存,最后注册 OkHttpUrlLoader,使 Glide 采用 OkHttp 进行网络请求。

  • 结合 OkHttp 实现 HTTP 缓存
  • 缓存控制策略:根据响应头的 Cache-Control 字段
  • 网络请求重试机制:3 次重试 + 指数退避

使用 Glide 加载图片

import android.os.Bundle;
import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView imageView = findViewById(R.id.imageView);
        String imageUrl = "https://example.com/image.jpg";

        Glide.with(this)
               .load(imageUrl)
               // 设置磁盘缓存策略为缓存所有类型的图片
               .diskCacheStrategy(DiskCacheStrategy.ALL)
               .into(imageView);
    }
}

在 MainActivity 中,我们使用 Glide 加载图片。通过 diskCacheStrategy(DiskCacheStrategy.ALL) 方法设置磁盘缓存策略,这里表示缓存所有类型的图片。 

 

简单概述:

  1. 内存缓存(手机内存)

    • 存最近看过的图,像手机相册最近项目
    • 优化:只存 15% 内存空间,自动清理不常用的
  2. 磁盘缓存(手机硬盘)

    • 存常用图的备份,像电脑硬盘
    • 优化:存 100MB,优先存高质量图
  3. 网络缓存(路由器缓存)

    • 存已经下载过的图,像小区快递柜
    • 优化:存 50MB,避免重复下载

具体概述

每一层的具体实现

1. 内存缓存(Memory Cache)
  • 作用:快速显示刚看过的图片(如滑动列表时来回切换的图片)
  • 实现
    • 使用 LruCache 算法(最近最少使用),自动清理长时间不用的图片
    • 限制:只占手机可用内存的 15%(例如手机有 8GB 内存,内存缓存约 1.2GB)
  • 优化
    • 图片按屏幕尺寸压缩(比如原图 2000px,手机屏幕 1000px,只存 1000px 版本)
    • 自动清理超出内存限制的图片
2. 磁盘缓存(Disk Cache)
  • 作用:存常用但暂时不在内存中的图片(如用户经常访问的商品详情页图片)
  • 实现
    • 使用 DiskLruCache 存储在手机硬盘
    • 限制:总容量 100MB,优先存高质量图片
  • 优化
    • 按 URL 哈希值命名文件,避免重复存储相同图片
    • 自动清理超过 7 天未使用的图片
3. 网络缓存(Network Cache)
  • 作用:避免重复从服务器下载相同图片(需结合 HTTP 缓存头)
  • 实现
    • 通过 OkHttp 的缓存机制,将图片存在路由器或基站缓存中
    • 限制:总容量 50MB,优先存高频访问的图片
  • 优化
    • 根据 HTTP 的Cache-Control头设置缓存时间(如设置为 1 天)
    • 图片 URL 带版本号(如image_v2.jpg),版本更新时强制重新下载

常见问题解决方案

1. 缓存穿透

Glide.with(context)
   .load(url)
   .error(R.drawable.ic_error) // 设置错误占位图
   .placeholder(R.drawable.ic_loading) // 设置加载占位图
   .fallback(R.drawable.ic_fallback) // 设置空值占位图
   .into(imageView);

2. 缓存雪崩 

int cacheDuration = TimeUnit.HOURS.toMillis(24) + new Random().nextInt(3600000);

3. OOM 预防

// 使用RGB_565格式减少内存占用
Glide.with(context)
   .load(url)
   .format(DecodeFormat.PREFER_RGB_565)
   .into(imageView);

关键指标的获取途径

  1. 冷启动加载时间
    • 工具运用:借助 Android Profiler 的 Timeline 功能来精准测量。
    • 操作办法:在应用启动时,启动 Profiler 并记录图片加载所耗费的时长。
    • 代码示例
long startTime = System.currentTimeMillis();
Glide.with(this).load(url).into(imageView);
long duration = System.currentTimeMillis() - startTime;
Log.d("GlideTest", "加载耗时: " + duration + "ms");
  1. 内存峰值占用情况
    • 工具选择:使用 Android Profiler 的 Memory Monitor 进行监测。
    • 操作步骤:在滑动列表时,留意 Heap Size 的变化趋势。
    • 优化要点:对比开启缓存前后,Bitmap 内存占用的差异。
  2. 缓存命中率计算
    • 工具利用:通过 Glide 的日志输出(设置Glide.get(context).setLogLevel(Log.DEBUG))。
    • 数据提取:从日志中筛选出FetchedDecoded相关的条目。
    • 计算公式:缓存命中率 = (内存命中数 + 磁盘命中数)÷ 总请求数 × 100%。
  3. FPS 帧率监控
    • 工具使用:采用 Android Profiler 的 FrameMetrics 功能。
    • 操作方式:在滑动列表的过程中,记录丢帧的数量。
    • 优化目标:确保平均帧率稳定在 55fps 以上。

扩展追问:

如何解决内存缓存导致的 OOM 问题?

动态尺寸压缩:

Glide.with(context)
    .load(url)
    .override(imageView.width, imageView.height)
    .into(imageView)

格式优化:优先使用 WebP 格式(体积减少 30%)

生命周期绑定:通过Glide.with(this)自动释放资源

内存监控:结合 Android Profiler 设置内存阈值报警

总结:通过合理配置和优化,可显著提升应用性能,降低用户流失率。建议开发者在新项目中优先采用 Glide 的三级缓存方案,并根据实际需求进行定制化调整。

感谢观看!!! 


http://www.kler.cn/a/592665.html

相关文章:

  • 小程序开发与物联网技术的结合:未来趋势
  • 网络编程(客户端间通信)
  • 【2025】基于python+django的小区物业管理系统(源码、万字文档、图文修改、调试答疑)
  • 深入解析 TouchSocket 插件系统架构与实践
  • k8s--集群内的pod调用集群外的服务
  • 穿越是时空之门(java)
  • 《深度学习》—— YOLOv1
  • 突破时空边界:Java实时流处理中窗口操作与时间语义的深度重构
  • 汇编移位指令
  • BERT系列模型
  • 解决下载npm 缓存出现的问题
  • JAVA并发-volatile底层原理
  • opencv初步学习——图像处理2
  • Day67 | 灵神 | 二分查找:统计公平数对的数目
  • SQLMesh系列教程:SQLMesh虚拟数据环境
  • 台式机电脑组装---电源
  • 【C++】STL(1) - 序列容器
  • Java设计模式之模板方法模式(Template Method Pattern)
  • Redis 三主三从集群部署的完整方案
  • ASP3605同步降压调节器——满足汽车电子严苛要求的电源芯片方案