题目
设计一个支持内存+磁盘双缓存的高性能图片加载库
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
内存管理,缓存策略,异步加载,图片处理,性能优化
快速回答
核心设计要点:
- 三级缓存架构:活动资源(弱引用)→ 内存缓存(LruCache)→ 磁盘缓存(DiskLruCache)
- 线程模型:主线程Handler更新UI + 线程池管理网络/磁盘IO + 后台线程解码
- 图片处理:Bitmap复用 + 采样压缩 + 内存计算策略
- 生命周期感知:通过Fragment监听宿主生命周期自动取消请求
- 防抖动优化:请求合并 + 加载优先级管理
1. 核心架构设计
三级缓存流程:
// 伪代码示例
Bitmap loadImage(String url) {
// 1. 检查活动资源(避免频繁GC)
if (activeResources.get(url) != null) {
return activeResources.get(url);
}
// 2. 检查内存缓存
Bitmap bitmap = memoryCache.get(url);
if (bitmap != null) {
activeResources.put(url, new WeakReference<>(bitmap));
return bitmap;
}
// 3. 检查磁盘缓存
File file = diskCache.get(url);
if (file.exists()) {
// 后台线程解码
bitmap = decodeSampledBitmap(file, reqWidth, reqHeight);
activeResources.put(url, new WeakReference<>(bitmap));
memoryCache.put(url, bitmap);
return bitmap;
}
// 4. 网络加载
InputStream is = downloadUrl(url);
diskCache.put(url, is); // 写入磁盘
// 重复步骤3的解码流程
}
2. 关键优化技术
内存缓存策略:
- 使用
LruCache+WeakReference双缓存层 - Bitmap内存计算:
bitmap.getByteCount()(API 19+)或width * height * 每像素字节数
图片压缩处理:
// 采样压缩示例
public static Bitmap decodeSampledBitmap(File file, int reqWidth, int reqHeight) {
// 1. 只解码边界信息
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file.getPath(), options);
// 2. 计算采样率
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// 3. 实际解码
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.RGB_565; // 减少内存
return BitmapFactory.decodeFile(file.getPath(), options);
}
3. 线程与生命周期管理
线程模型:
- 固定大小线程池处理网络请求
- 单线程池处理磁盘IO(避免并发锁竞争)
- Handler将结果切回主线程
生命周期集成:
// 在Activity中添加不可见Fragment
public class RequestManagerFragment extends Fragment {
@Override
public void onDestroy() {
// 取消所有关联请求
imageLoader.cancelRequests(this);
}
}
// 发起请求时绑定
imageLoader.load(url).with(activity).into(imageView);
4. 高级优化技巧
- Bitmap复用:使用
BitmapFactory.Options.inBitmap(需API 11+) - 请求合并:对相同URL的请求进行去重
- 磁盘缓存优化:使用
DiskLruCache而非SQLite - 内存抖动预防:避免在循环中创建Bitmap
5. 常见错误
- ❌ 未处理View复用导致的图片错位
- ❌ 内存缓存未考虑Configuration变化
- ❌ 未限制并发线程数导致OOM
- ❌ 磁盘缓存未做LRU清理
- ❌ 忽略网络状态(如WiFi下预加载)
6. 扩展知识
- Glide源码设计:Engine加载机制/Resource回收策略
- Bitmap内存演进:Android 8.0引入的
NativeAllocationRegistry - 新兴技术:Coil的Kotlin协程实现/Picasso的Transformer链
- 监控工具:结合
StrictMode检测主线程IO