volley笔记--开篇:RequestQueue

前言

volley使用已久,一直想阅读下其源码,然后对比现在常用的一些网络框架,然后对网络这块能有更加的理解。
大致的想法是:先了解volley的整体框架,再逐个理清涉及到的各个知识点。然后,再涉及一下OkHttp等,进而再去了解下http的协议细节,从而对网络这块能有个充分的认识。
android上手之时太过仓促,基础这块一直觉得不够扎实。而在我看来,对基础技术的掌握应该是和对业务需求的理解同样重要的。

正文

volley相关的文章虽不至多如牛毛但也不少,大致分为两类:分析原理和侧重应用。
讲应用的可以参考:郭神的几篇博客;原理分析比较好的有这篇:
http://a.codekk.com/detail/Android/grumoon/Volley%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90
其实这篇文章已经将volley的骨架讲得很清楚了。而我想做是,记录我自己阅读理解的这个过程。

概述

volley由两部分组成:核心部分和toolbox中的工具类。

volley核心类图

RequestQueue

用过volley的都清楚,咱们的起手式:Volley.newRequestQueue(context)创建一个queue然后调用add()就可以发起网络请求了。而这招就是创建一个RequestQueue,看它位置那么中间一看就很重要。

RequestQueue顾名思义:请求队列,带了一票的成员和方法。
RequestQueue本质:存储请求然后让dispatcher来处理请求。这话有两层意思:1)它存储各类请求;2)它驱使dispatcher。

1,先跳过RequestQueue的创建看它的start。

public void start() {
        stop();  // Make sure any currently running dispatchers are stopped.
        // Create the cache dispatcher and start it.
        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
        mCacheDispatcher.start();

        // Create network dispatchers (and corresponding threads) up to the pool size.
        for (int i = 0; i < mDispatchers.length; i++) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                    mCache, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }
    }

start中初始化了CacheDispatcher和NetworkDispatcher。这两类dispatcher就好比两类工种,他们是Request的具体执行者。当然,不同工种的工作量不同。所以,CacheDispatcher只有一个,NetworkDispatcher是一组,NetworkDispatcher的数量是在创建RequestQueue时指定的,当然volley也设了默认值:DEFAULT_NETWORK_THREAD_POOL_SIZE=4。

2,dispatcher们的创建

public CacheDispatcher(
            BlockingQueue<Request<?>> cacheQueue, BlockingQueue<Request<?>> networkQueue,
            Cache cache, ResponseDelivery delivery)
public NetworkDispatcher(BlockingQueue<Request<?>> queue,
            Network network, Cache cache,
            ResponseDelivery delivery)

mCacheQueue和mNetworkQueue分别是用于缓存和网络两个优先级阻塞队列。而mCache和mNetwork分别是实现缓存和网络的两把工具,在RequestQueue的创建时被传入,这两把工具分别有两个接口:Cache和Network。volley定义了这两把工具的功能要求,君可按这标准自己做两把称手的家伙,如果木有也没事,volley默认提供两把:DiskBasedCache(基于文件的缓存策略)和BasicNetwork。
(点评:可扩展&面向接口编程的完美体现,这两个默认实现类自然是放在toolbox目录中)。

至于ResponseDelivery的默认实现ExecutorDelivery被放在了核心包中,可能是由于结果分发这块相比于缓存和网络实在没什么花头吧。

3,Request的添加

public <T> Request<T> add(Request<T> request) {
        // Tag the request as belonging to this queue and add it to the set of current requests.
        request.setRequestQueue(this);
        synchronized (mCurrentRequests) {
            mCurrentRequests.add(request);
        }

        // Process requests in the order they are added.
        request.setSequence(getSequenceNumber());
        request.addMarker("add-to-queue");

        // If the request is uncacheable, skip the cache queue and go straight to the network.
        if (!request.shouldCache()) {
            mNetworkQueue.add(request);
            return request;
        }

        // Insert request into stage if there's already a request with the same cache key in flight.
        synchronized (mWaitingRequests) {
            String cacheKey = request.getCacheKey();
            if (mWaitingRequests.containsKey(cacheKey)) {
                // There is already a request in flight. Queue up.
                Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
                if (stagedRequests == null) {
                    stagedRequests = new LinkedList<Request<?>>();
                }
                stagedRequests.add(request);
                mWaitingRequests.put(cacheKey, stagedRequests);
                if (VolleyLog.DEBUG) {
                    VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
                }
            } else {
                // Insert 'null' queue for this cacheKey, indicating there is now a request in
                // flight.
                mWaitingRequests.put(cacheKey, null);
                mCacheQueue.add(request);
            }
            return request;
        }
    }

add的流程:1)不需要缓存的(Request默认开启缓存)就直接扔进mNetworkQueue;2)需要缓存的,先检测mWaitingRequests(保存了出于等待状态的请求)判断请求是否重复,不重复就记录请求并扔进mCacheQueue。
大致呢就是:每个请求过来先在mCurrentRequests登记姓名。不要缓存的直接扔给网络dispatcher,可以缓存的扔给缓存dispatcher,同一个缓存还来就给我在mWaitingRequests里按Cachekey排排站好。

4,RequestQueue的总结
RequestQueue创建的时候需要三把工具(缓存Cache、网络Network、结果分发ResponseDelivery),然后自己再创建了几个存储队列(mCacheQueue、mNetworkQueue),利用这两样东西创建了CacheDispatcher和networkDispatcher。
接着,视情况分配Request给不同的dispatcher来处理。它提供了Request执行完成后的善后方法(finish),但没负责Request的善后。

技术细节

1,在操作mCurrentRequests和mWaitingRequests添加和删除的每一处都是用了同步机制,利用的是java的对象锁,不得不说synchronized(Object)真方便,比C语言实现同步便利得多。
1-1)mCurrentRequests类型是HashSet,而mWaitingRequests是HashMap。mCurrentRequests仅需要添加和删除不需要索引,为何还要涉及hash。照我的理解如果不需要索引单就保存来说应当是极好实现的,不知用HashSet是否是出于利于存储方面的考虑,作为遗留问题后续阅读源码再加分析。
1-2)Set和Map是不带同步机制的,之前看ArrayList等源码的时候,貌似同步是可以通过Collections.synchronizedList来加持一层同步buff从而实现的。那为何此处并未使用Collections机制,是考虑方便还是其它,留待用到再深究。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值