Volley源码学习笔记_RequestQueue和BasicNetWork

来源:互联网 发布:软件侵权被起诉 编辑:程序博客网 时间:2024/06/01 09:31

1.开始

Volley也只是听过没用过,新接的项目里面请求用的是Volley,只能赶鸭子上架的看了些简单的使用。现在理解下源码。(ps:这里不涉及有关图片相关的部分pps:理解不对的地方请指出,灰常感谢)

2.Volley的使用

关于Volley的使用,比较简洁的。

  //首先创建请求队列  RequestQueue requestQueue = Volley.newRequestQueue(Context);  //创建一个request  Request request=new Request() {...};  //将request添加到请求队列中  requestQueue.add(request);

下面根据上面的三行代码,来一步步的看相关的实现源码。

3.RequestQueue

我们先看 new RequestQueue的代码,它只传入了一个Context

 public static RequestQueue newRequestQueue(Context context) {        return newRequestQueue(context, (HttpStack)null);    } public static RequestQueue newRequestQueue(Context context, HttpStack stack) {        File cacheDir = new File(context.getCacheDir(), "volley");        String userAgent = "volley/0";        try {            String network = context.getPackageName();            PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);            userAgent = network + "/" + queue.versionCode;        } catch (NameNotFoundException var6) {            ;        }        if(stack == null) {            if(VERSION.SDK_INT >= 9) {                stack = new HurlStack();            } else {                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));            }        }        BasicNetwork network1 = new BasicNetwork((HttpStack)stack);        RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);        queue1.start();        return queue1;    }

以上代码包含的内容还是很多的。主要是先根据VERSION.SDK_INT
来判断使用什么网络连接请求类。然后实例化一个BasicNetWork来进行网络交互请求。 然后创建一个请求队列,传入一个DiskBasedCache,一个BasicNetwork,最后队列start。下面先看一下RequestQueue的构造函数。

   public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {       //下面这5个有的是直接在外面初始化的        this.mSequenceGenerator = new AtomicInteger();        this.mWaitingRequests = new HashMap();        this.mCurrentRequests = new HashSet();        this.mCacheQueue = new PriorityBlockingQueue();        this.mNetworkQueue = new PriorityBlockingQueue();        //这里        this.mCache = cache;        this.mNetwork = network;        this.mDispatchers = new NetworkDispatcher[threadPoolSize];        this.mDelivery = delivery;    }    public RequestQueue(Cache cache, Network network, int threadPoolSize) {        this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper())));    }    public RequestQueue(Cache cache, Network network) {        this(cache, network, 4);    }

从下往上, this(cache, network, 4);这是的4就是线程数目,记得之前好像还是可以自己输入的现在默认是4个。这里有一个ExecutorDelivery,主要作用就是传递消息(response),可以看到它的实现要传递一个Handler。这个后期再看。下面看一下RequestQueue的start()。

   public void start() {        this.stop();        this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);        this.mCacheDispatcher.start();        for(int i = 0; i < this.mDispatchers.length; ++i) {            NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);            this.mDispatchers[i] = networkDispatcher;            networkDispatcher.start();        }    }

从上面可以看出,只要new了一个RequestQueue那么就会开启1个缓存线程,4个网络请求
线程。这就意味着一次最多只能并发5个线程,如果缓存线程没有命中,那么最多并发4个网
络请求线程。NetworkDispatcher基本就是从队列中获取请求,然后请求网络数据
(BasicNetWork)同时更新到UI线程。(ExecutorDelivery)。

既然是队列了,那他是如何addRequest的呢?

 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.        //请求不用缓存就加入到网络请求队列中,但是这个值默认是true        if (!request.shouldCache()) {            mNetworkQueue.add(request);            return request;        }//根据key值判断请求是否已经在重复请求队列,但是会发现最终都是要添加到这个队列里面的        // 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<>();                }                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;        }    }

RequestQueue的add方法,从这里我们可以看到四个参数 mWaitingRequests ,mCurrentRequests ,mCacheQueue ,mNetworkQueue。分别是重复请求队列,当前请求或者等待请求集合,缓存队列,网络请求队列,这里重复队列就是一个Map集合,key是cacheKey,就是getUrl。mCacheQueue ,mNetworkQueue是一个优先级队列 。根据优先级来执行,同等优先级是无序的。
当mCacheQueue或者mNetworkQueue利用add方法添加请求之后,在运行的线程就会接收到请求(Cache线程接收到请求,会将相应的请求提那家到mNetworkQueue,这样在请求线程中就可以处理请求队列中的请求),从而去处理相对应的请求,最后将处理的结果由mDelivery来发送到主线程进行更新。


BasicNetWork的具体作用有:

1)对于已经有缓存的请求,添加其头部信息,如下:
    private void addCacheHeaders(Map<String, String> headers, Entry entry) {        if(entry != null) {            if(entry.etag != null) {                headers.put("If-None-Match", entry.etag);            }            if(entry.serverDate > 0L) {                Date refTime = new Date(entry.serverDate);                headers.put("If-Modified-Since", DateUtils.formatDate(refTime));            }        }    }
2)调用 HttpStack 对象去网络中获取数据,返回httpResonse 对象。
 httpResponse = this.mHttpStack.performRequest(request, e);
3)根据状态编码来返回不同的NetworkResponse对象

如304(未修改)就返回缓存中的数据,如果不是,则根据响应中的数据,重新构造一个NetworkResponse对象。

   if(networkResponse1 == 304) {                    return new NetworkResponse(304, request.getCacheEntry().data, responseHeaders1, true);                }                 ...  long requestLifetime = SystemClock.elapsedRealtime() - requestStart;                this.logSlowRequests(requestLifetime, request, responseContents1, statusCode2);                if(networkResponse1 >= 200 && networkResponse1 <= 299) {                    return new NetworkResponse(networkResponse1, responseContents1, responseHeaders1, false);                }                ...  NetworkResponse networkResponse = null;                if(httpResponse == null) {                    throw new NoConnectionError(var15);                }                int statusCode1 = httpResponse.getStatusLine().getStatusCode();                VolleyLog.e("Unexpected response code %d for %s", new Object[]{Integer.valueOf(statusCode1), request.getUrl()});                if(responseContents == null) {                    throw new NetworkError(networkResponse);                }                networkResponse = new NetworkResponse(statusCode1, (byte[])responseContents, responseHeaders, false);                if(statusCode1 != 401 && statusCode1 != 403) {                    throw new ServerError(networkResponse);                }             
4)BasicNetwork实现了重试的机制

如果第一次从网络获取失败,默认会重新再尝试一次,如果失败,则会将Error返回,默认的实现类是DefaultRetryPolicy类。

   private static void attemptRetryOnException(String logPrefix, Request<?> request, VolleyError exception) throws VolleyError {        RetryPolicy retryPolicy = request.getRetryPolicy();        int oldTimeout = request.getTimeoutMs();        try {            retryPolicy.retry(exception);        } catch (VolleyError var6) {            request.addMarker(String.format("%s-timeout-giveup [timeout=%s]", new Object[]{logPrefix, Integer.valueOf(oldTimeout)}));            throw var6;        }        request.addMarker(String.format("%s-retry [timeout=%s]", new Object[]{logPrefix, Integer.valueOf(oldTimeout)}));    }

下面看一下3的内容

//具体代码就不贴了   public NetworkResponse performRequest(Request<?> request) throws VolleyError {   ....}
public interface Network {    NetworkResponse performRequest(Request<?> var1) throws VolleyError;}

BasicNetwork是Network 的实现类。。Network 的方法只有一个performRequest(),参数是Request。用来获取网络请求到的数据,然后在NetworkDispatcher中被解析后通过ExecutorDelivery将请求结果传到UI线程。
这里有一段代码:

  byte[] responseContents1;                if(httpResponse.getEntity() != null) {                    responseContents1 = this.entityToBytes(httpResponse.getEntity());                } else {                    responseContents1 = new byte[0];                } if(networkResponse1 >= 200 && networkResponse1 <= 299) {                    return new NetworkResponse(networkResponse1, responseContents1, responseHeaders1, false);                }

这是请求到数据的时候,然后在状态码返回200-299之间的时候创建一个NetworkResponse对象并将其data设置为获取到内容。除了在状态码304的时候,还有一个地方也创建了NetworkResponse对象。这里的responseContents是开始创建的一个空对象。

  networkResponse = new NetworkResponse(statusCode1, (byte[])responseContents, responseHeaders, false);                if(statusCode1 != 401 && statusCode1 != 403) {                    throw new ServerError(networkResponse);                }

以上。不对的地方麻烦大家指出,非常感谢。

参考

[1].http://blog.csdn.net/linmiansheng/article/details/22653841

[2].http://blog.csdn.net/mr_liabill/article/details/50241543
[3].http://f303153041.iteye.com/blog/2281350