Volley简单学习使用四——Dispatcher分析

一、Volley工作流程图:

继续从CacheDispatcher和NetworkDispatcher开始看起。

二、CacheDispatcher:

一个线程,用于调度处理走缓存的请求。启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery 去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher去调度处理。

(一)看源码前,先看一下从其成员变量与处理流程:

(1). 成员变量

BlockingQueue<Request<?>>
mCacheQueue
     缓存请求队列

BlockingQueue<Request<?>> mNetworkQueue 网络请求队列

Cache mCache                                                缓存类,代表了一个可以获取请求结果,存储请求结果的缓存

ResponseDelivery mDelivery                        请求结果传递类

(2). 处理流程图

(3)源码:

1、构造函数:一系列赋值初始化操作

    /**
     * Creates a new cache triage dispatcher thread.  You must call {@link #start()}
     * in order to begin processing.
     */
    public CacheDispatcher(BlockingQueue<Request> cacheQueue, BlockingQueue<Request> networkQueue,
            Cache cache, ResponseDelivery delivery) {
        mCacheQueue = cacheQueue;
        mNetworkQueue = networkQueue;
        mCache = cache;
        mDelivery = delivery;
    }

提到使用CacheDispatcher时一定要调用start()方法;而CacheDispatcher的创建与线程start都是在RequestQueue中的add()函数中实现的:

    // Create the cache dispatcher and start it.
    mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
    mCacheDispatcher.start();

2、既然是线程,重点看其run()函数:

    @Override
    public void run() {
        //设置优先级
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        // Make a blocking call to initialize the cache.
        //这里的Cache其实是DiskBasedCache,见附I
        mCache.initialize();

        /*****循环处理逻辑******/
        while (true) {
            try {
                // 从缓存队列 mCacheQueue中取出一个Request;如果mCacheQueue为空,则阻塞进行忙等待
                final Request request = mCacheQueue.take();
                request.addMarker("cache-queue-take");

                // 如果取出的Request请求已经被取消,则直接finish,处理下一个request
                if (request.isCanceled()) {
                    request.finish("cache-discard-canceled");
                    continue;
                }

                // 尝试从缓存中获取request对应的结果
                Cache.Entry entry = mCache.get(request.getCacheKey());

                //为null,表示该cacheKey对应缓存结果不存在,则直接将request添加到mNetworkQueue中
                if (entry == null) {
                    request.addMarker("cache-miss");
                    mNetworkQueue.put(request);
                    continue;
                }

                //如果缓存结果存在,但是已过期,同样也是将request添加到mNetworkQueue中
                if (entry.isExpired()) {
                    request.addMarker("cache-hit-expired");
                    request.setCacheEntry(entry);
                    mNetworkQueue.put(request);
                    continue;
                }

                // 如果命中(hit)找到了对应的缓存结果,则解析其数据为Response并返回给该request
                request.addMarker("cache-hit");
                Response<?> response = request.parseNetworkResponse(
                        new NetworkResponse(entry.data, entry.responseHeaders));
                request.addMarker("cache-hit-parsed");

                // 还需判断缓存结果是否时间过久已经不新鲜,是否需要refresh
                if (!entry.refreshNeeded()) {
                  // 不需要Refresh,则直接由mDelivery提交给相应的request
                    mDelivery.postResponse(request, response);
                } else {
                    // 如果已经不新鲜,mDelivery依旧提交结果给request,
                  // 但同时要将Request传递给mNetworkQueue进行新鲜度验证
                    request.addMarker("cache-hit-refresh-needed");
                    request.setCacheEntry(entry);

                    // Mark the response as intermediate.
                    response.intermediate = true;

                    // Post the intermediate response back to the user and have
                    // the delivery then forward the request along to the network.
                    mDelivery.postResponse(request, response, new Runnable() {
                        @Override
                        public void run() {
                            try {
                                mNetworkQueue.put(request);
                            } catch (InterruptedException e) {
                            }
                        }
                    });
                }

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

附I)这里的Cache实际是DiskBasedCache,mCache.initialize()实际上调用的是DiskBasedCache.initialize():

    /**
     * Initializes the DiskBasedCache by scanning for all files currently in the
     * specified root directory. Creates the root directory if necessary.
     */
    public synchronized void initialize()

三、NetworkDispatcher

一个线程,用于调度处理网络的请求。启动后会不断从网络请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给 ResponseDelivery 去执行后续处理,并判断结果是否要进行缓存。

(1). 成员变量

BlockingQueue<Request<?>>
mQueue
 网络请求队列

Network mNetwork                             网络类,代表了一个可以执行请求的网络

Cache mCache                                    缓存类,代表了一个可以获取请求结果,存储请求结果的缓存

ResponseDelivery mDelivery           请求结果传递类,可以传递请求的结果或者错误到调用者

(2). 处理流程图

(3).先看其构造函数,与CacheDispatcher的逻辑处理大致相同:

    /**
     * Creates a new network dispatcher thread.  You must call {@link #start()}
     * in order to begin processing.
     */
    public NetworkDispatcher(BlockingQueue<Request> queue,
            Network network, Cache cache,
            ResponseDelivery delivery) {
        mQueue = queue;
        mNetwork = network;
        mCache = cache;
        mDelivery = delivery;
    }

(4).其run()函数:

    @Override
    public void run() {
    //设为后台进程
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        Request request;
        /*********循环处理逻辑********/
        while (true) {
            try {
                // 从网络请求队列中取出request,同理mQueue为空时,也是忙等待
                request = mQueue.take();
            } catch (InterruptedException e) {
                if (mQuit) {
                    return;
                }
                continue;
            }

            try {
                request.addMarker("network-queue-take");

                // 如果取出的Request请求已经被取消,则直接finish,处理下一个request
                if (request.isCanceled()) {
                    request.finish("network-discard-cancelled");
                    continue;
                }

                // Tag the request (if API >= 14)
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
                }

                // 通过Network执行Request,获得NetworkResponse,故网络请求的处理逻辑应该都封装在了Network中
                NetworkResponse networkResponse = mNetwork.performRequest(request);
                request.addMarker("network-http-complete");

                // 用来验证新鲜度,(notModified=304)响应为304且请求已经有了Response传输情况
                if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                    request.finish("not-modified");
                    continue;
                }

                // 将NetworkResponse解析为Response
                Response<?> response = request.parseNetworkResponse(networkResponse);
                request.addMarker("network-parse-complete");

                // 如果request可以被缓存,并且其请求实体补位空,则添加到mCache中
                // TODO: Only update cache metadata instead of entire record for 304s.
                if (request.shouldCache() && response.cacheEntry != null) {
                    mCache.put(request.getCacheKey(), response.cacheEntry);
                    request.addMarker("network-cache-written");
                }

                // 传输Response
                request.markDelivered();
                mDelivery.postResponse(request, response);
            } catch (VolleyError volleyError) {
                parseAndDeliverNetworkError(request, volleyError);
            } catch (Exception e) {
                VolleyLog.e(e, "Unhandled exception %s", e.toString());
                mDelivery.postError(request, new VolleyError(e));
            }
        }
    }
时间: 2024-10-12 19:48:18

Volley简单学习使用四——Dispatcher分析的相关文章

Volley简单学习使用四——源码分析二

一.Volley工作流程图: 继续从CacheDispatcher和NetworkDispatcher开始看起. 二.CacheDispatcher: 一个线程,用于调度处理走缓存的请求.启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery 去执行后续处理.当结果未缓存过.缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher去调度处理. (一)看源码前,先看一下从其成员变量与处理流程: (1). 成员

Volley简单学习使用三——源码分析一(修改)

一.Volley框架图 根据图简单猜测Volley工作的流程,见右下角的注释,蓝色表示主线程(main thread),绿色表示缓存线程(cache thread),黄色表示网络线程(network threads): 再寻找图中的关键字:queue(RequestQueue),cache queue,CacheDispatcher,NetworkDispatcher; 流程可简单那描述为:RequestQueue的add()操作将Request添加到缓存队列cache queue中.Cache

Volley简单学习使用三——源码分析一

一.Volley框架图 根据图简单猜测Volley工作的流程,见右下角的注释,蓝色表示主线程(main thread),绿色表示缓存线程(cache thread),黄色表示网络线程(network threads): 再寻找图中的关键字:queue(RequestQueue),cache queue,CacheDispatcher,NetworkDispatcher; 流程可简单那描述为:RequestQueue的add()操作将Request添加到缓存队列cache queue中.Cache

Volley简单学习使用二——Request

一.首先从每个POST或者GET请求的构造主体看起:XXXRequest (一)StringRequest 源码如下: public class StringRequest extends Request<String> { private final Listener<String> mListener; /** * 可以看到最终构造请求交由Request类去实现,HTTP的请求和响应均是由Request去处理 * * @param method the request {@li

Volley简单学习使用一

一.简介: Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身,既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载网络上的图片.除了简单易用之外,Volley在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕. Volley应该是简

cocos2dx 3.1从零学习(四)——内存管理(错误案例分析)

本篇内容文字比较较多,但是这些都是建立在前面三章写代码特别是传值的时候崩溃的基础上的.可能表达的跟正确的机制有出入,还请指正. 如果有不理解的可以联系我,大家可以讨论一下,共同学习. 首先明确一个事实,retain和release是一一对应的,跟new和delete一样. 1.引用计数retain release 这里请参考一下引用计数的书籍,肯定说的比我讲的详细. 简单一点理解就是,对new的指针加一个计数器,每引用一次这块内存,计数就加1.在析构的时候减1,如果等于0的时候就delete这个

Android中关于JNI 的学习(四)简单的例子,温故而知新

在第零篇文章简单地介绍了JNI编程的模式之后,后面两三篇文章,我们又针对JNI中的一些概念做了一些简单的介绍,也不知道我到底说的清楚没有,但相信很多童鞋跟我一样,在刚开始学习一个东西的时候,入门最好的方式就是一个现成的例子来参考,慢慢研究,再学习概念,再回过来研究代码,加深印象,从而开始慢慢掌握. 今天我们就再来做一个小Demo,这个例子会比前面稍微复杂一点,但是如果阅读过前面几篇文章的话,理解起来也还是很简单的.很多东西就是这样,未知的时候很可怕,理解了就很简单了. 1)我们首先定义一个Jav

EasyUI学习总结(四)——parser源码分析

EasyUI学习总结(四)--parser源码分析 parser模块是easyloader第一个加载的模块,它的主要作用,就是扫描页面上easyui开头的class标签,然后初始化成easyui控件. 1 /** 2 * parser模块主要是解析页面中easyui的控件 3 */ 4 $.parser = { 5 // 是否自动解析 6 auto: true, 7 8 // 可以被解析的控件 9 plugins:['linkbutton','menu','menubutton','splitb

正式学习React(四) ----Redux源码分析

今天看了下Redux的源码,竟然出奇的简单,好吧.简单翻译做下笔记: 喜欢的同学自己可以去github上看:点这里 createStore.js 1 import isPlainObject from 'lodash/isPlainObject' 2 import $$observable from 'symbol-observable' 3 4 /** 5 * These are private action types reserved by Redux. 6 * For any unkno