volley的使用方式大致如下:
<span style="font-size:18px;"><span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>RequestQueue </span><span style="font-family: Arial, Helvetica, sans-serif;">mRequestQueue = Volley.newRequestQueue(mContext.getApplicationContext());</span></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size:18px;"></span></span><pre name="code" class="java"><span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>XXRequest request = new XXRequest(Method.XX, "URL", </span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>new Response,Listener<XXX>(){ </span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>@Override</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>public void onResponse(XXX response){</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>//do something</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>}</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>}, new Response.ErrorListener(){</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>@Override</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>public void onErrorResponse(VolleyError error){</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>//do something</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>}</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>});</span>
<span style="font-size:18px;"><span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>mRequestQueue.add(</span><span style="font-family: Arial, Helvetica, sans-serif;">request </span><span style="font-family: Arial, Helvetica, sans-serif;">);</span></span>
看了几遍volley的源代码,大致记录下volley的工作过程。
1. Volley.newRequestQueue(Context context)创建mRequestQueue并调用其start()函数,start函数中开启若干个线程,包括一个CacheDispatcher,若干个NetworkDispatcher,这些线程会一直在后台运行。
2. mRequestQueue.add(request),首先将request加入CurrentRequest(一个HashSet,注意request finish时会将其从该Set中移除),在判断request是否需要缓存,如果不需要,直接加入NetworkQueue,
否则判断WaitingRequests(一个HashMap)是否已经有URL相同的request在通信中,如下:
<span style="font-size:18px;">synchronized (mWaitingRequests) {
String cacheKey = request.getCacheKey();</span>
<span style="font-size:18px;"><span style="white-space:pre"> </span> //判断是否在WaitingRequests中
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;
}</span>
如果有则则将其加入对应key的stagedRequests中(表示已经有相同的request在执行),否则将其加入CacheQueue
3. CahceDispather从CacheQueue中取request,判断是否在缓存中,如果request.getCacheKey()对应的Cache.Entry为null或者该entry失效了,将其加入NetworkQueue,否则根据这些信息生成response,如下:
<span style="font-size:18px;">Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));</span>
然后判断request是否需要更新,不需要直接:
<span style="font-size:18px;">mDelivery.postResponse(request, response);</span>
mDelivery是一个继承自Executor的ResponseDelivery类的对象,实际则为ExecutorDelivery,实际这个方法开启新线程又调用了request的方法:
<span style="font-size:18px;">if (mResponse.isSuccess()) {
mRequest.deliverResponse(mResponse.result);
} else {
mRequest.deliverError(mResponse.error);
}</span>
而这两个方法中执行的便是最初传入的两个Listener中的方法,很明显此时不在主线程中,如果要根据返回值跟新UI,最好传入一个Handler进行操作
如果需要更新,如下:<span style="font-size:18px;">mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});</span>
多开启一个线程将将request加入NetworkQueue中,很明显不可能一开始Cache中就有数据,最初的数据都是通过NetworkDispatcher通过网络获得的,
4.NetworkDispatcher从NetworkQueue中获取request,首先:
<span style="font-size:18px;">NetworkResponse networkResponse = mNetwork.performRequest(request);
</span>
这时Network起作用了,它里面有一个HttpStack,这一步得追溯到最初Volley对RequestQueue的建立:<span style="font-size:18px;">if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
Network network = new BasicNetwork(stack);</span>
其中stack即为HttpStack实例,HurlStack和HttpClientStack都继承自HttpStack(主要讨论volley工作流程,网络我也不太懂),显然此处获得了NetworkResponse后,后续工作就与步骤3中差不多了,如下:
<span style="font-size:18px;">Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
// Write to cache if applicable.
// TODO: Only update cache metadata instead of entire record for 304s.
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
// Post the response back.
request.markDelivered();
mDelivery.postResponse(request, response);</span>
注意如果需要缓存的话,需要将request对应的CacheKey和cacheEntry加入Cache中,而markDelivered抑制request生命周期中相同的反应