简单图片加载框架的打造(二)-分发器设计RequestQueue

Posted by 夏敏的博客 on July 17, 2017

上一章链接:简单图片加载框架的打造(一)-框架设计

与Volley的代码一样,RequestQueue就是参考Volley设计的.

RequestQueue的方法

RequestQueue代码设计

RequestQueue作为分发的源头,其一定持有一个Queue,然后持有Dispatchers来处理队列里面的请求.

既然需要队列,我们这种生产者消费者模式对队列的要求是:

  • 线程安全
  • 能够阻塞
  • 能够优先级控制

这样我们的数据结构只能是: PriorityBlockingQueue

我们还需要分发器,从PriorityBlockingQueue中不断的take(), 然后进行处理, 因此我们需要一个分发器列表.这里参考Volley源码,使用一个数组来存储,毕竟数组够完成任务了.

private RequestDispacher[] mRequestDispachers;

我们还需要提供方法去让主程序start自己.stop自己.
因此有了UML里面的start方法,stop方法.在这两个方法里面我们就开启分发器,关闭分发器就行了.

分发器RequestDispacher设计

分发器从PriorityBlockingQueue中取请求, 我大Java可没有那种什么全局变量的玩意儿,把PriorityBlockingQueue的引用传给RequestDispacher就行了,然后里面开一个线程不断的跑,从队列里取东西,进行消费就行了.

那么我们的RequestDispacher就可以写成继承于Thread类, 正好也有start/stop方法可以供调用.

代码编写

在往RequesQueue添加请求的时候,我们可以直接给ImageView设置加载中的图片,虽然这个请求还未被处理,也就是还未被加载中,但是宏观来说,进入了我们的ImageLoader就已经是加载中了.

public class RequestQueue {

    BlockingQueue<BitmapRequest> mRequestQueue = new PriorityBlockingQueue<>();

    private AtomicInteger mNo = new AtomicInteger(0);

    private int mThreadCount;

    private RequestDispacher[] mRequestDispachers;

    public RequestQueue(int threadCount) {
        mThreadCount = threadCount;

    }

    /**
     * start各个分发器
     */
    public void start() {
        mRequestDispachers = new RequestDispacher[mThreadCount];
        for (int i = 0; i < mRequestDispachers.length; i++) {
            RequestDispacher dispacher = new RequestDispacher(mRequestQueue);
            mRequestDispachers[i] = dispacher;
            dispacher.start();
        }
    }

    /**
     * 停止所有请求,以interrupt异常的方式
     * 分发器也会停止运行
     */
    public void stop() {
        for (int i = 0; i < mRequestDispachers.length; i++) {
            if (mRequestDispachers[i] != null) {
                mRequestDispachers[i].quit();
            }
        }
    }


    /**
     * 取消所有请求,但不停止分发器的运行
     */
    public void cancel() {
        for (BitmapRequest request : mRequestQueue) {
            request.setCancel(true);
        }
    }

    /**
     * 根据tag取消请求
     * @param tag
     */
    public void cancel(Object tag) {
        if (tag == null) {
            return;
        }

        for (BitmapRequest request : mRequestQueue) {
            if (tag.equals(request.getRequestTag())) {
                request.setCancel(true);
            }
        }
    }

    public void addRequest(BitmapRequest request) {
        if (!mRequestQueue.contains(request)) {
            /** 设置唯一标识 */
            request.setSerialNo(mNo.incrementAndGet());
            mRequestQueue.add(request);
            L.w("请求添加成功, 编号为:" + request.getSerialNo());
        } else {
            L.w("请求已经存在, 编号为:" + request.getSerialNo());
        }
        if (request.getDisplayConfig() != null
                && request.getDisplayConfig().loadingImage != -1) {
            ImageView imageView = request.getImageView();
            if (imageView != null && imageView.getTag().equals(request.getImageURL())) {
                imageView.setImageResource(request.getDisplayConfig().loadingImage);
            }
        }
    }
}

分发器的代码


/**
 * 请求转发线程
 * 依赖于BitmapRequest
 * 依赖于Loader
 * Created by xiamin on 7/8/17.
 */
public class RequestDispacher extends Thread {

    private BlockingQueue<BitmapRequest> mBitmapRequests;

    /** Used for telling us to die. */
    private volatile boolean mQuit = false;


    public RequestDispacher(BlockingQueue<BitmapRequest> requests) {
        mBitmapRequests = requests;
    }

    /**
     * Forces this dispatcher to quit immediately.  If any requests are still in
     * the queue, they are not guaranteed to be processed.
     */
    public void quit() {
        mQuit = true;
        interrupt();
    }

    @Override
    public void run() {
        /**不断获取请求,处理请求*/
        while (!isInterrupted()) {
            try {
                BitmapRequest bitmapRequest = mBitmapRequests.take();

                if (bitmapRequest.isCancel()) {
                    continue;
                }
                L.d("开始处理" + bitmapRequest.getSerialNo() + "号请求,线程号:" + Thread.currentThread()
                        .getId());
                /**
                 * 处理请求对象
                 */
                String type = parseURL(bitmapRequest.getImageURL());
                ILoader l = LoaderManager.getInstance().getLoaderByType(type);
                l.loadImage(bitmapRequest);

            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                e.printStackTrace();
                if (mQuit) {
                    return;
                }
                continue;
            }
        }
    }

    /**
     * 解析图片来源
     * @param imageURL
     * @return
     */
    private String parseURL(String imageURL) {
        if (imageURL.contains("://")) {
            return imageURL.split("://")[0];
        }

        L.e("不支持的URL:" + imageURL);
        return " ";

    }
}

下一章

下一章将讲解加载器缓存器的设计:简单图片加载框架的打造(三)-加载器缓存器设计

工程路径,里面还有我准备写的数据库lib,还有httplib,只看ImageLoaderlib即可. https://github.com/Jerey-Jobs/Sherlock


本文作者:Anderson/Jerey_Jobs

博客地址 : http://jerey.cn/
简书地址 : Anderson大码渣
github地址 : https://github.com/Jerey-Jobs

作者:Anderson大码渣,欢迎关注我的简书: Anderson大码渣