一、背景
在日常 Android 开发中,使用 Glide 加载图片是非常常见的场景,尤其是在 RecyclerView 列表中。
但当图片数量较多时,往往会遇到以下问题:
❌ 图片加载过多,导致卡顿
❌ 滑动时疯狂请求图片,影响流畅度
❌ 重复加载同一 URL,浪费资源
❌ 并发过高,导致线程竞争严重
👉 虽然 Glide 本身已经做了优化,但在某些场景下(如图片瀑布流、车辆图片列表等),仍然需要更精细的控制策略。
二、优化思路
本方案核心目标:
✅ 控制最大并发加载数量
✅ 避免重复加载同一 URL
✅ 支持任务队列(类似线程池调度)
✅ 支持滑动暂停/恢复加载
✅ 避免内存泄漏(WeakReference)
三、核心实现
1️⃣ GlideQueueManager 完整代码
bash
/**
* Author: Su
* Date: 2026/3/20
* Description: 优化后的 Glide 串行加载管理器
*/
public class GlideQueueManager {
// ✅ 任务队列
private final Queue<Runnable> taskQueue = new LinkedList<>();
// ✅ 正在执行任务数量
private int runningCount = 0;
// ✅ 最大并发任务数
private final int maxConcurrent = 3;
// ✅ 已经在队列中的 URL(避免重复加载)
private final Set<String> loadingUrls = new HashSet<>();
// ✅ 是否暂停队列(快速滑动时可暂停)
private boolean isPaused = false;
/**
* 串行 / 并行加载图片
*/
public synchronized void loadImageSerial(String path, ImageView imageView, int placeholder, int error) {
// 防止重复加载
if (loadingUrls.contains(path)) return;
loadingUrls.add(path);
WeakReference<ImageView> imageRef = new WeakReference<>(imageView);
taskQueue.offer(() -> {
ImageView iv = imageRef.get();
if (iv == null) {
onTaskFinished(path);
return;
}
Glide.with(iv)
.load(path)
.override(200, 200)
.thumbnail(0.2f)
.placeholder(placeholder)
.error(error)
.fitCenter()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.skipMemoryCache(false)
.dontAnimate()
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
onTaskFinished(path);
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
onTaskFinished(path);
return false;
}
})
.into(iv);
});
// 启动队列
runNext();
}
/**
* 执行下一个任务
*/
private synchronized void runNext() {
if (isPaused) return;
while (runningCount < maxConcurrent && !taskQueue.isEmpty()) {
Runnable task = taskQueue.poll();
if (task != null) {
runningCount++;
task.run();
}
}
}
/**
* 任务完成回调
*/
private synchronized void onTaskFinished(String path) {
loadingUrls.remove(path);
runningCount--;
runNext();
}
/**
* 暂停队列(例如 RecyclerView 快速滑动时)
*/
public synchronized void pause() {
isPaused = true;
}
/**
* 恢复队列
*/
public synchronized void resume() {
isPaused = false;
runNext();
}
/**
* 清空队列(页面销毁时调用)
*/
public synchronized void clear() {
taskQueue.clear();
loadingUrls.clear();
runningCount = 0;
}
/**
* RecyclerView 滑动绑定方法
*/
public void bindRecyclerViewScroll(RecyclerView recyclerView) {
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView rv, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
resume();
} else {
pause();
}
}
});
}
}
四、核心设计解析
1️⃣ 队列 + 并发控制
bash
private final Queue<Runnable> taskQueue = new LinkedList<>();
private int runningCount = 0;
private final int maxConcurrent = 3;
👉 类似一个简易线程调度器
- taskQueue:任务排队
- runningCount:当前执行数
- maxConcurrent:最大并发
✔ 控制同时最多加载 3 张图片,避免"爆炸式请求"
2️⃣ 防重复加载
bash
private final Set<String> loadingUrls = new HashSet<>();
👉 作用:
同一个 URL 不会重复进入队列
避免 RecyclerView 复用导致的重复请求
3️⃣ WeakReference 防内存泄漏
bash
WeakReference<ImageView> imageRef = new WeakReference<>(imageView);
👉 避免:
- Activity 销毁但任务仍持有 ImageView
- 导致内存泄漏
4️⃣ 滑动优化(关键点🔥)
bash
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
resume();
} else {
pause();
}
👉 效果:
- 快速滑动 👉 暂停加载
- 停止滑动 👉 恢复加载
✔ 极大提升滑动流畅度
5️⃣ 自动调度机制
bash
runNext();
👉 每个任务结束后:
- 释放一个并发位
- 自动执行下一个任务
✔ 实现"持续消费队列"
五、使用方式
1️⃣ 初始化
bash
GlideQueueManager manager = new GlideQueueManager();
2️⃣ 加载图片
bash
manager.loadImageSerial(url, imageView, R.drawable.placeholder, R.drawable.error);
3️⃣ 绑定 RecyclerView
bash
manager.bindRecyclerViewScroll(recyclerView);
4️⃣ 页面销毁
bash
manager.clear();
六、优化效果
实际项目优化后效果:
- 🚀 滑动更流畅(无明显卡顿)
- 📉 请求数量明显下降
- 🔁 无重复加载问题
- 💾 内存使用更稳定
七、适用场景
特别适用于:
- 🚗 车辆图片列表(你这个 PDI 场景很适合)
- 🛒 商品列表
- 📷 瀑布流图片
- 🧾 大量缩略图展示
八、总结
相比直接使用 Glide:
👉 本方案相当于在 Glide 外层加了一层"调度系统"
核心价值:
- 控制节奏(限流)
- 避免浪费(去重)
- 提升体验(滑动优化)