Android网络框架-Volley(三) CacheDispatcher和NetworkDispatcher源码分析

Android网络框架-Volley(一) 工作原理分析 中的流程图中我们知道Volley工作是有三个线程的:主线程、缓存线程和网络线程。这些线程的工作是建立在RequestQueue上的,上一篇文章 Android网络框架-Volley(二) RequestQueue源码分析以及建立一个RequestQueue 中我们分析了RequestQueue的源码以及最佳使用方式,这篇文章我们来分析两大管家CacheDispatcher和NetworkDispatcher

当一个request加入到RequestQeue中后,首先是交给CacheDispatcher的,我们分析一个CacheDispatcher的源码

public class CacheDispatcher extends Thread {

    //缓存队列
    private final BlockingQueue
   
   
    
     mCacheQueue;

    //网络队列
    private final BlockingQueue
    
    
     
      mNetworkQueue;

    //cache实例,从cache中取出的数据是一个Entry
    private final Cache mCache;

    //将数据交给主线程
    private final ResponseDelivery mDelivery;


    /**
     *构造方法
     *
     * @param cacheQueue 缓存队列
     * @param networkQueue 网络队列
     * @param cache Cache
     * @param delivery 分发者(用于将数据分发给主线程)
     */
    public CacheDispatcher(
            BlockingQueue
     
     
      
       cacheQueue, BlockingQueue
      
      
       
        networkQueue,
            Cache cache, ResponseDelivery delivery) {
        mCacheQueue = cacheQueue;
        mNetworkQueue = networkQueue;
        mCache = cache;
        mDelivery = delivery;
    }

    /**
     * 强制退出
     */
    public void quit() {
        mQuit = true;
        interrupt();
    }
    //CacheDispatcher是一个线程,在RequestQueue中的start()方法中调用了
    //CacheDispatcher的start()方法,之后会执行run()方法
    @Override
    public void run() {
        if (DEBUG) VolleyLog.v("start new dispatcher");
        //设置一个优先级,这是标准的后台线程优先级,稍微比普通优先级低一些
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

        // 阻塞初始化cache实例
        mCache.initialize();
        //缓存线程开始循环执行
        while (true) {
            try {
                // 阻塞方法,直到从缓存队列中取出一个request,才会往下执行
                final Request request = mCacheQueue.take();
                request.addMarker("cache-queue-take");

                // 如果这个request已经被取消了,那么就不往下执行了
                if (request.isCanceled()) {
                    request.finish("cache-discard-canceled");
                    continue;
                }

                // 从cache中取出数据,取出的数据是一个Entry。里面保存了数据还有一些
                //头部信息
                Cache.Entry entry = mCache.get(request.getCacheKey());
                //如果entry为空,说明缓存中不存在此数据
                if (entry == null) {
                    request.addMarker("cache-miss");
                    //直接加入到网络队列中,从网络中去获取数据
                    mNetworkQueue.put(request);
                    continue;
                }

                // 如果entry完全过期了,那就加入到网络队列中,重新去获取数据
                //判断过期的方法为entry中的ttl
       
       <当前系统时间,则为过期 if (entry.isexpired()) { request.addmarker("cache-hit-expired"); request.setcacheentry(entry); mnetworkqueue.put(request); continue; } cache命中了,把entry中保存的data和头部信息解析出来 request.addmarker("cache-hit"); response
         response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); //没有过期,也不需要刷新,将他交付给主线程显示出来。 if (!entry.refreshNeeded()) { //由delivery交付给主线程 mDelivery.postResponse(request, response); } else { // entry过期但没有完全过期,是需要刷新的状态,那么就先将其 //交付给主线程显示出来,然后再加入到网络线程中,去获取最新数据 request.addMarker("cache-hit-refresh-needed"); request.setCacheEntry(entry); // 将response标记为待完成状态,需要更新 response.intermediate = true; // 又delivery将数据分发给主线程之后再加入到网络队列中去 mDelivery.postResponse(request, response, new Runnable() { @Override public void run() { try { //加入到网络队列中去 mNetworkQueue.put(request); } catch (InterruptedException e) { } } }); } } catch (InterruptedException e) { if (mQuit) { return; } continue; } } } } 
       
      
      
     
     
    
    
   
   
有几种情况会吧request加入到网络队列中去获取数据
1.缓存中没有数据,直接到网络中去获取
2.缓存中有数据,但是已经完全过期,直接到网络中去获取
3.缓存中有数据,已经过期但没有完全过期,是一个需要刷新的状态,先将数据交给主线程,再到网络中获取最新数据,然后刷新
接下来我们分析NetworkDispatcher的源码
public class NetworkDispatcher extends Thread {
    //需要处理的request的队列
    private final BlockingQueue
    
    
     
      mQueue;
    //处理网络数据的接口
    private final Network mNetwork;
    //cache实例
    private final Cache mCache;
    //分发者,将获取到的数据分发给主线程
    private final ResponseDelivery mDelivery;

    /**
     * 构造方法
     *
     * @param queue待处理的request的队列
     * @param network 处理请求的网络接口
     * @param cache Cache 
     * @param delivery 分发者
     */
    public NetworkDispatcher(BlockingQueue
     
     
      
       queue,
            Network network, Cache cache,
            ResponseDelivery delivery) {
        mQueue = queue;
        mNetwork = network;
        mCache = cache;
        mDelivery = delivery;
    }

    /**
     *强制退出
     */
    public void quit() {
        mQuit = true;
        interrupt();
    }
    //和CacheDispatcher一样,在RequestQueue中调用start()方法后,调用了
    //NetworkDispatcher的start()方法,即调用了这个run()方法
    @Override
    public void run() {
        //设置优先级,标准后台线程优先级,略低于普通线程
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        Request request;
        while (true) {
            try {
                // 阻塞方法,从request队列中取出要执行的request
                request = mQueue.take();
            } catch (InterruptedException e) {
                // 判断是否要退出
                if (mQuit) {
                    return;
                }
                continue;
            }

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

                //如果当前request已经取消,则不继续执行
                if (request.isCanceled()) {
                    request.finish("network-discard-cancelled");
                    continue;
                }

                // 如果当前手机版本是4.0以上的,则给该request设置一个tag作为标记
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
                }

                // 处理网络请求,返回响应数据
                NetworkResponse networkResponse = mNetwork.performRequest(request);
                request.addMarker("network-http-complete");

                // 如果服务器返回304,或者我们已经请求过一次了,则不再去请求数据
                if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                    //finish掉这个request
                    request.finish("not-modified");
                    continue;
                }

                // 在工作线程中去解析响应数据
                Response
      
       response = request.parseNetworkResponse(networkResponse);
                request.addMarker("network-parse-complete");

                //如果可以缓存,则缓存到cache中
                if (request.shouldCache() && response.cacheEntry != null) {
                    mCache.put(request.getCacheKey(), response.cacheEntry);
                    request.addMarker("network-cache-written");
                }

                // 给request一个标记,标记为该request已经被处理完,分发到主线程中
                request.markDelivered();
                //由delicery将最后的数据交付给主线程
                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));
            }
        }
    }
}
     
     
    
    
总结:
1.当一个request加入到requestQueue中,首先会交到CacheDispatcher手中。
    1.1.request请求的数据在缓存中
        1.1.1.数据已经完全过期,则将request交给NetworkDispatcher去从网络获取数据。执行2
        1.1.2.数据已经过期,但没有完全过期,需要刷新,则先将数据交付给主线程去显示,再交给NetworkDispatcher去从网路上获取最新数据,然后再交给主线程去更新。执行2
        1.1.3.数据没有过期,则直接从缓存中获取数据后,交付给主线程去显示
    1.2.request请求的数据没在缓存中,则交给NetworkDispatcher去从网络上获取。执行2
2.此时NetworkDispatcher拿到了request,到网络中去获取数据
    2.1.数据可以写到缓存,则将数据写到缓存,并且交付给主线程去显示
    2.2.数据不可以写到缓存,则直接交付给主线程去显示
     

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值