Volley源码学习笔记_RequestQueue和BasicNetWork
2017-06-07 17:38
337 查看
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的代码,它只传入了一个Contextpublic 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
相关文章推荐
- Volley源码学习笔记_Request
- Volley源码学习笔记_ExecutorDelivery
- Volley源码学习笔记_CacheDispatcher和NetworkDispatcher
- prototype.js 源码学习笔记(二)
- LDD3源码学习笔记之scull_pipe转
- 学习笔记:解读CppUnit源码7
- Ubuntu学习笔记(1)---编译源码包
- 2410 TFTP源码 学习笔记414757749
- jQuery源码学习笔记八
- 学习笔记:解读CppUnit源码3
- JAVA虚拟机源码学习笔记之二
- Struts 源码学习笔记
- jQuery源码学习笔记三(转)
- jQuery源码学习笔记五(转)
- jQuery源码学习笔记一
- jQuery源码学习笔记四
- (源码实例)通过层DIV实现,当鼠标放在链接上面,显示图片及文字 - 流星絮语 JAVA学习笔记 - CSDNBlog
- shell脚本学习笔记(三)mysql与ARP表的绑定源码
- spring学习笔记之AbstractController源码解读
- jQuery源码学习笔记二(转)