[特殊字符] Glide 图片加载优化:自定义队列管理器(支持并发控制 + 防抖 + 滑动优化)

一、背景

在日常 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 外层加了一层"调度系统"

核心价值:

  • 控制节奏(限流)
  • 避免浪费(去重)
  • 提升体验(滑动优化)
相关推荐
Greenland_128 天前
Android Java使用Glide无法生成GlideApp
android·java·glide
pvIaUtLZ1 个月前
每个支路的三相阻抗矩阵
glide
CjQYqIyjLwCW2 个月前
Halcon联合C#开发最新版实用框架 实际项目应用验证过的版本,源码,修改了大量Bug以适合...
glide
a3158238062 个月前
Android 大图显示策略优化显示(二)
android·java·开发语言·javascript·kotlin·glide·图片加载
青春勿语3 个月前
Lumen:重新定义 Android 图片加载体验
android·glide
灵感菇_3 个月前
Android图片加载框架 Glide全面解析
android·缓存·glide
Lei活在当下3 个月前
【项目踩坑实录】并发环境下,Glide缓存引起的图片加载异常
android·debug·glide
某空m3 个月前
【Android】Glide的缓存机制
android·缓存·glide
某空m3 个月前
【Android】Glide的使用
android·glide