上一篇(http://blog.csdn.net/szxgg/article/details/51345859)讲述了当我们调用Volley.newRequest()时,Volley内部这个类做了什么,其实Volley这个类就做了一件事情,就是实例化了RequesQueue,这也符合设计模式中的单一职责,其实主要的处理都在其他类中,有三个类最重要,HttpStack/Network/RequestQueue,之后会讲解这些类的关系及作用,那首先还是结合我们使用Volley时的情形来看看源码内部执行流程吧。
我们在实例化RequestQueue后,如果要请求,那么得做两件事
1)实例化Request对象
StringRequest request = new StringRequest(Request.Method.GET, "www.58.com", new Response.Listener<String>() { @Override public void onResponse(String s) { } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { } });
2)将Request对象加入到RequestQueue中
mQueue.add(request);
首先Request有很多种,我们这一篇先不细究,只用StringRequest来进行演示.
当这么做了后,会发现结果的回调回到生成requset时传入的参数Response.Listener中,失败的结果会回调到Response.ErrorListener中,那么这一切是怎么发生的呢?需要看源码来进行解释了。
首先生成request对象,然后把request对象加入到requestQueue中,那一定是requestQueue对象得到request后进行的处理,那么就看看requestQueue,add(request)这个方法,总共做了如下几件事情:
1)给传入的request设置requestQueue,就是当前的实例,这样 对于request就与requestQueue产生了联系,那么如果有多个requestQueue时,具体的request属于哪个requestQueue就能知道了
request.setRequestQueue(this);
2)把传入的request加入到当前队列中
synchronized(this.mCurrentRequests) { this.mCurrentRequests.add(request); }
然后给requset设置了一些标记,无关紧要
3)判断request是不是应该缓存,---这个标志是在生成request后可以手动设置的,默认是应该缓存
如果不应该缓存,直接把request加入到networkQueue中,返回
if(!request.shouldCache()) { this.mNetworkQueue.add(request); return request; }
如果应该缓存,则
A.得到request的缓存key
String cacheKey = request.getCacheKey();
默认是method:url
B.如果waitingRequest中包含这个缓存key,则根据缓存key去waitingRequest中去找value
if(this.mWaitingRequests.containsKey(cacheKey)) { Object stagedRequests = (Queue)this.mWaitingRequests.get(cacheKey);
B1.如果stagedRequests为空,则实例化为一个LinkedList
<span style="white-space:pre"> </span>stagedRequests = new LinkedList();
B2.把request加入到这个stagedRequests中
<span style="white-space:pre"> </span>((Queue)stagedRequests).add(request);
B3.waitingRequest根据cacheKey存入这个stagedRequests值
<span style="white-space:pre"> </span>this.mWaitingRequests.put(cacheKey, stagedRequests);
C.如果waitingRequest不包含这个缓存key,则存入waitingRequests中,并且value为null,也存入cacheQueue
<span style="white-space:pre"> </span>this.mWaitingRequests.put(cacheKey, (Object)null); this.mCacheQueue.add(request);
按照上面的逻辑当我们生成cacheKey为get:www.baidu.com的request时,第一次请求时会把这个request放入waitingRequest和cacheQueue中
第二次再请求时,会给他的waitingQueue中的value生成LinkedList并把request放入其中,请求两次后waitingRequest才圆满,至于这样做有啥用还有几个request作用先不管。
到这一步,requestQueue.add(request)方法就结束了,主要干了下面几件事:
1.给request绑定
2.将request加入到currentRequests(HashSet)中
3.判断request需不需要缓存(默认需要)
如果不需要缓存,直接把request加入到networkQueue中
如果需要缓存,先从waitingRequest找,然后设置加入到ccheQueue中(两次)
requestQueue有几个和request产生关联的数据结构
1.
private final Set<Request<?>> mCurrentRequests;
2.
private final Map<String, Queue<Request<?>>> mWaitingRequests;
3.
private final PriorityBlockingQueue<Request<?>> mCacheQueue;
4.
private final PriorityBlockingQueue<Request<?>> mNetworkQueue;
那么到底在哪发生的请求呢,好像add方法中并没有啊,上一篇中生成requestQueue时,requestQueue最后调用了,queue.start(),去看看那个方法。
1.调用了stop方法可以看做在start前进行的一个清空操做
public void stop() { if(this.mCacheDispatcher != null) { this.mCacheDispatcher.quit();//thread.interrupt } for(int i = 0; i < this.mDispatchers.length; ++i) { if(this.mDispatchers[i] != null) { this.mDispatchers[i].quit();//thread.interrupt } } }
2.生成cacheDispatcher,并且start
this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery); this.mCacheDispatcher.start();
cacheDispatcher是一个Thread,就是执行了CacheDispatcher的run方法
实例化时,传入了cacheQueue和networkQueue,这两个就是上文提到的add中的两个,还传入了cache和Delivery,Cache是缓存用的,Delivery主要进行回调操作
然后根据构造RequestQueue时的threadPoolSize,实例化NetworkDispatcher的个数,并调用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(); }
相比CacheDispatcher,NetworkDispatcher实例化时少传了一个CacheQueue,多传了一个Network,这个network就是Volley中实例化RequestQueue时生成的
RequestQueue和CacheDispatcher以及NetworkDispatcher产生联系是通过cacheQueue和networkQueue生成的,那么接下来分析下这两个thread的run方法。
CacheDispatcher.run():
1)首先初始化缓存Cache---目前是DefaultBaseCache
this.mCache.initialize();
然后无限的循环while(true)
2)从cacheQueue中寻找临近的Request
while(true) { final Request e = (Request)this.mCacheQueue.take();
3)根据request的cacheKey,去Cache中寻找Entry
Entry entry = this.mCache.get(e.getCacheKey());
4)如果entry为空或者过期了,就把这个request加入到networkQueue中
if(entry == null) { e.addMarker("cache-miss"); this.mNetworkQueue.put(e); } else if(entry.isExpired()) { e.addMarker("cache-hit-expired"); e.setCacheEntry(entry); this.mNetworkQueue.put(e); }
5)如果entry没有过期,那么就不去网络取了,直接调用这个request.parseNetworkResponse
Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
数据就是从Cache中得到的Entry的值
6)判断是否需要刷新,如果需要,就当这次请求回来后再把这个request再次放到networkQueue中,再次去请求新的数据下次用
if(entry.refreshNeeded()) { ... this.mDelivery.postResponse(e, response, new Runnable() { public void run() { try { CacheDispatcher.this.mNetworkQueue.put(e); } catch (InterruptedException var2) { ; } } });
7)如果不需要刷新,就只执行Delievery的postResponse操作
this.mDelivery.postResponse(e, response);
上述是CacheDispatcher的run方法,主要做了几件事情,首先从CacheQueue中寻找这个request,如果存在且没过期就直接通过这个request得到缓存起来的结果,返回
否则就把它加入到NetworkQueue中,而这个NetworkQueue的实例同样也是NetworkDispatcher中的,那么就看看NetworkDispatcher,这里面就是网络访问的东西
NetworkDispatcher.run();
1)循环的从mQueue也就是NetworkQueue中寻找Request(就是CacheDispatcher有的存入操作/addQueue中也有)
while(true) { ... try { request = (Request)this.mQueue.take(); break; } catch (InterruptedException var6) { if(this.mQuit) { return; } } }
2)调用network方法去处理这个request
NetworkResponse e = this.mNetwork.performRequest(request);
网络请求就在这里了!!!!
3)调用request的请求把networkResponse转化成对外暴露的Response,并通过Delievery返回
Response volleyError1 = request.parseNetworkResponse(e); //request.addMarker("network-parse-complete") if(request.shouldCache() && volleyError1.cacheEntry != null) { this.mCache.put(request.getCacheKey(), volleyError1.cacheEntry); request.addMarker("network-cache-written"); } request.markDelivered(); this.mDelivery.postResponse(request, volleyError1); }
基本上大致的流程就这样。
首先将request加入到requestQueue中,如果request不需要缓存,那么直接将这个request添加到networkQueue中,否则加入到cacheQueue中,cacheQueue在CacheDispatcher中,CacheDispatcher无限循环的去在cacheQueue中拿request,如果request满足条件,那直接不请求,转成需要的response回调回去,否则再把这个request放到networkQueue中,而netWorkDispatcher中有这个networkQueue的实例,则会找到后通过network.perfromRequest来找结果,解析回调
因此网络访问就是在Network的performRequest中去的,那这个Network我们目前用的是BasicNetwork,所以需要看看这里面的代码
BasicNetwork.performRequest()
1)调用其内部的HttpStack.performRequest().得到HttpResponse
httpResponse = this.mHttpStack.performRequest(request, e);
2)把HttpResponse转化成NetworkResponse
... if(httpResponse.getEntity() != null) { responseContents1 = this.entityToBytes(httpResponse.getEntity()); } else { responseContents1 = new byte[0]; } long requestLifetime1 = SystemClock.elapsedRealtime() - requestStart; this.logSlowRequests(requestLifetime1, request, responseContents1, statusCode1); if(networkResponse1 >= 200 && networkResponse1 <= 299) { return new NetworkResponse(networkResponse1, responseContents1, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart); }
其实质还是HttpStack.performRequest
SDK>=9,用的是HurlStack,其他用的是HttpClientStack
这里面才是真正的调用网络,connection什么的
因此访问网络:
NetworkQueue中有,取出,调用Network.performRequest()-------HttpStack.performRequest()
得到HttpResponse----转成NetworkResponse------用request自己转成Response
调用Delievery----最后回调到自己的request.delieveryResponse()/request.delieverError()
整体流程就是这样,那么还有些细节性的问题需要研究
比如Cache到底是怎样的
Delievery是怎样从子线程切换到主线程回调给调研者的
还有HttpStack类,Network类,Delievery类,Request类的类图和作用,请看后续文章