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

一、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-12-12 17:25:03

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

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

[Android]Volley源码分析(二)Cache

Cache作为Volley最为核心的一部分,Volley花了重彩来实现它.本章我们顺着Volley的源码思路往下,来看下Volley对Cache的处理逻辑. 我们回想一下昨天的简单代码,我们的入口是从构造一个Request队列开始的,而我们并不直接调用new来构造,而是将控制权反转给Volley这个静态工厂来构造. com.android.volley.toolbox.Volley: public static RequestQueue newRequestQueue(Context conte

集合类学习之Arraylist 源码分析

1.概述 ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小. 每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小.它总是至少等于列表的大小(如果不指定capacity,默认是10).    /**      * Constructs an empty list with an initial capacity of ten.

Tomcat源码分析二:先看看Tomcat的整体架构

Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Connector.Container等组件,接下来我们一起去大致的看看这些组件的作用和他们之间的相互联系.在这之前,我们先补充一个知识点,也就是Tomcat它实现的功能点是什么呢?通过查找一些资料,这里参考下极客时间<深入拆解Tomcat_Jetty>中的总结,即Tomcat 要实现 2 个核心功能:

netty 源码分析二

以服务端启动,接收客户端连接整个过程为例分析, 简略分为 五个过程: 1.NioServerSocketChannel 管道生成, 2.NioServerSocketChannel 管道完成初始化, 3.NioServerSocketChannel注册至Selector选择器, 4.NioServerSocketChannel管道绑定到指定端口,启动服务 5.NioServerSocketChannel接受客户端的连接,进行相应IO操作 Ps:netty内部过程远比这复杂,简略记录下方便以后回忆

哇!板球 源码分析二

游戏主页面布局 创建屏下Score标签 pLabel = CCLabelTTF::create("Score", "Arial", TITLE_FONT_SIZE); //分数标签 //设置标签字体的颜色 pLabel->setColor (ccc3(0, 0, 0)); //设置文本标签的位置 pLabel->setPosition ( ccp ( SCORE_X, //X坐标 SCORE_Y //Y坐标 ) ); //将文本标签添加到布景中 this

baksmali和smali源码分析(二)

这一节,主要介绍一下 baksmali代码的框架. 我们经常在反编译android apk包的时候使用apktool这个工具,其实本身这个工具里面对于dex文件解析和重新生成就是使用的baksmali 和smali这两个jar包其中 baksmali是将 dex文件转换成便于阅读的smali文件的,具体使用命令如下:java -jar baksmali.jar classes.dex -o myout其中myout是输出的文件夹 而smali是将smali文件重新生成回 dex文件的具体使用的命

【梦幻连连连】源码分析(二)

转载请注明出处:http://blog.csdn.net/oyangyufu/article/details/24736711 GameLayer场景界面效果: 源码分析: GameLayer场景初始化,主要是初始化加载界面及背景音乐 bool GameLayer::init() { float dt=0.0f; if ( !CCLayerColor::initWithColor(ccc4(255, 255, 255, 255))) { return false; } this->initLoa