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

来源:互联网 发布:阿里在线编程难么 编辑:程序博客网 时间:2024/05/24 05:36

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

原创粉丝点击