ImageLoader源码解析(五) 补充 针对ListView或者RecycleView的优化

本文详细解析了ImageLoader中PauseOnScrollListener类的工作原理,该类针对ListView、GridView及RecycleView进行了滑动时暂停加载图片的优化处理,并介绍了ImageLoader如何通过暂停和恢复加载任务来实现这一功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ImageLoader源码解析(五) 补充 针对ListView或者RecycleView的优化

1 前言

前几篇,我忽略了一个类,这个类在com.nostra13.universalimageloader.core.listener包下,它所做的事情是,针对ListView,GridView,RecycleView做优化,其实很简单,就是在滑动的时候暂停加载,在滑动结束后重新启动加载,我们来看下这个类

2 PauseOnScrollListener

public class PauseOnScrollListener implements OnScrollListener {

    private ImageLoader imageLoader;

    private final boolean pauseOnScroll;
    private final boolean pauseOnFling;
    private final OnScrollListener externalListener;

    /**
     * Constructor
     *
     * @param imageLoader   {@linkplain ImageLoader} instance for controlling
     * @param pauseOnScroll Whether {@linkplain ImageLoader#pause() pause ImageLoader} during touch scrolling
     * @param pauseOnFling  Whether {@linkplain ImageLoader#pause() pause ImageLoader} during fling
     */
    public PauseOnScrollListener(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling) {
        this(imageLoader, pauseOnScroll, pauseOnFling, null);
    }

    /**
     * Constructor
     *
     * @param imageLoader    {@linkplain ImageLoader} instance for controlling
     * @param pauseOnScroll  Whether {@linkplain ImageLoader#pause() pause ImageLoader} during touch scrolling
     * @param pauseOnFling   Whether {@linkplain ImageLoader#pause() pause ImageLoader} during fling
     * @param customListener Your custom {@link OnScrollListener} for {@linkplain AbsListView list view} which also
     *                       will be get scroll events
     */
    public PauseOnScrollListener(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling,
            OnScrollListener customListener) {
        this.imageLoader = imageLoader;
        this.pauseOnScroll = pauseOnScroll;
        this.pauseOnFling = pauseOnFling;
        externalListener = customListener;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        switch (scrollState) {
            case OnScrollListener.SCROLL_STATE_IDLE:
                imageLoader.resume();
                break;
            case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                if (pauseOnScroll) {
                    imageLoader.pause();
                }
                break;
            case OnScrollListener.SCROLL_STATE_FLING:
                if (pauseOnFling) {
                    imageLoader.pause();
                }
                break;
        }
        if (externalListener != null) {
            externalListener.onScrollStateChanged(view, scrollState);
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (externalListener != null) {
            externalListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
        }
    }

这个类其实也没什么可讲的,就是根据状态变化,是否暂停加载,滑动结束后再启动加载,
在使用的时候.其实对于RecycleView是否可用,我没事试过,但是它提供了一个思路,一个实现滑动暂停加载的思路,RecycleView也有监听滑动的方法,再写一个类似的就ok了

其实最重要的是Imageloader是如何完成暂停和继续逻辑的

3 Imageloader.pause和resume

  • Imagelader
  public void pause() {
        engine.pause();
    }

    /**
     * Resumes waiting "load&display" tasks
     */
    public void resume() {
        engine.resume();
    }

可以看到,所有的操作又转到了ImageLoaderEngine

  • ImageLoaderEngine
    private final AtomicBoolean paused = new AtomicBoolean(false);
    private final AtomicBoolean networkDenied = new AtomicBoolean(false);
    private final Object pauseLock = new Object();
 void pause() {
        paused.set(true);
    }

    /**
     * Resumes engine work. Paused "load&display" tasks will continue its work.
     */
    void resume() {
        paused.set(false);
        synchronized (pauseLock) {
            pauseLock.notifyAll();
        }
    }

      AtomicBoolean getPause() {
        return paused;
    }

暂停的,只是设置了一下标志,唤醒,则是通过lock,唤醒所有在等待的线程

那么到底是在哪里暂停的呢

  • LoadAndDisplayImageTask

    @Override
    public void run() {
        if (waitIfPaused()) return;
        ....
    }
 /**
     * 任务是否暂停
     *
     * @return <b>true</b> - if task should be interrupted; <b>false</b> - otherwise
     */
    private boolean waitIfPaused() {
        AtomicBoolean pause = engine.getPause();
        if (pause.get()) {
            synchronized (engine.getPauseLock()) {
                if (pause.get()) {
                    L.d(LOG_WAITING_FOR_RESUME, memoryCacheKey);
                    try {
                    //核心代码,本线程等待
                        engine.getPauseLock().wait();
                    } catch (InterruptedException e) {
                        L.e(LOG_TASK_INTERRUPTED, memoryCacheKey);
                        return true;
                    }
                    L.d(LOG_RESUME_AFTER_PAUSE, memoryCacheKey);
                }
            }
        }
        //如果view已经被回收或者被重用,那么暂停
        return isTaskNotActual();
    }

到这里就已近很明白了,,其实Imagloader并不能做到中断加载的线程,而是,在加载之前判断一下是否暂停,并不会影响已近在加载的东西,不过这样,也已近做的很好了,至少滑动后,才会加载显示的图片,不用加载

PS :最近项目中遇到一个问题,重写GridView嵌套进ScrollView中,如果重写的是GridView的测量方法,会破坏GrideView的重用机制,导致内存占用过多,所以还是使用头布局/尾部局,或者ViewType来做比较好

4 总结

暂停和重新开水线程,用到了同步代码块和对象监视器,下面是一个参考,可以参照着看一下
http://xiemingmei.iteye.com/blog/1073940

5 解析源码地址

https://github.com/yizeliang/Android-Universal-Image-Loader

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值