这篇博客想写挺久的了,因为之前接触到网络请求的第一个流行的库就是Volley
,在使用的时候也感觉到它的功能和拓展性的强大,但是一直没有去探究他内部的流程,同时可以发现网上对Volley
这个框架设计的评价都非常好,所以去了解内部的实现还是很有必要的。下面开始吧。
先从最开始怎么去使用说起,最常见的使用方式就是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| RequestQueue queue = Volley.newRequestQueue(this); StringRequest request = new StringRequest("http://70kg.info", new Response.Listener<String>() { @Override public void onResponse(String response) { } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); queue.add(request);
|
先去创建一个RequestQueue
,然后在去创建一个request
,最后加入到队列里面就可以了。使用也是相当的方便清晰。那就从RequestQueue
入手,看看这个队列是什么样的。
RequestQueue
这个类是在toolbox
包里面,都是一下已经给我们实现一些功能的类,方便我们去使用。Volley.newRequestQueue(this);
最终走到了这里:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public static RequestQueue newRequestQueue(Context context, HttpStack stack) { File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); String userAgent = "volley/0"; try { String packageName = context.getPackageName(); PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); userAgent = packageName + "/" + info.versionCode; } catch (NameNotFoundException e) { } if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { stack = new HurlStack(); } else { stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } } Network network = new BasicNetwork(stack); RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); queue.start(); return queue; }
|
这里可以看到还有个userAgent
,在使用使用HttpClientStack
也就是API<9,使用`androidhttpclient`的时候使用,具体是什么会在下面的参考中给出,和本文关系不是很大,只要明白在>=9的时候使用了HurlStack
,内部是HttpURLConnection
就差不多了。下面还有个Network
,是根据传进去的stack
来选择不同的处理网络方式,后面会说。最重要的就是下面两行,真正的new RequestQueue
,然后star
,进去看看:9,使用`androidhttpclient`的时候使用,具体是什么会在下面的参考中给出,和本文关系不是很大,只要明白在>
经过各种重载构造函数,走到了这个:
1 2 3 4 5 6 7 8 9 10 11
| public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { mCache = cache; mNetwork = network; mDispatchers = new NetworkDispatcher[threadPoolSize]; mDelivery = delivery; }
|
然后就是去看start
方法了:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public void start() { stop(); mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start(); for (int i = 0; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } }
|
所以当我们新建了一个RequestQueue
之后,其实是启动了5个线程在跑。接下来就是queue.add(request);
的时候了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public Request add(Request request) { request.setRequestQueue(this); synchronized (mCurrentRequests) { mCurrentRequests.add(request); } request.setSequence(getSequenceNumber()); request.addMarker("add-to-queue"); if (!request.shouldCache()) { mNetworkQueue.add(request); return request; } synchronized (mWaitingRequests) { String cacheKey = request.getCacheKey(); if (mWaitingRequests.containsKey(cacheKey)) { Queue<Request> stagedRequests = mWaitingRequests.get(cacheKey); if (stagedRequests == null) { stagedRequests = new LinkedList<Request>(); } stagedRequests.add(request); mWaitingRequests.put(cacheKey, stagedRequests); } else { mWaitingRequests.put(cacheKey, null); mCacheQueue.add(request); } return request; } }
|
CacheDispatcher
Volley默认都是可以缓存的,而处理缓存的是CacheDispatcher
,这是一个线程,那就可以去Run
方法看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); mCache.initialize(); while (true) { try { final Request request = mCacheQueue.take(); request.addMarker("cache-queue-take"); if (request.isCanceled()) { request.finish("cache-discard-canceled"); continue; } Cache.Entry entry = mCache.get(request.getCacheKey()); if (entry == null) { request.addMarker("cache-miss"); mNetworkQueue.put(request); continue; } if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); mNetworkQueue.put(request); continue; } request.addMarker("cache-hit"); Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); if (!entry.refreshNeeded()) { mDelivery.postResponse(request, response); } else { request.setCacheEntry(entry); response.intermediate = true; mDelivery.postResponse(request, response, new Runnable() { @Override public void run() { try { mNetworkQueue.put(request); } catch (InterruptedException e) { } } }); } } catch (InterruptedException e) { if (mQuit) { return; } continue; } } }
|
整个过程差不多都注释了,再来个大招,非常棒的流程图:
CacheDispatcher
说完缓存分发,还有网络分发,还是看run方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Request request; while (true) { try { request = mQueue.take(); } catch (InterruptedException e) { if (mQuit) { return; } continue; } try { request.addMarker("network-queue-take"); if (request.isCanceled()) { request.finish("network-discard-cancelled"); continue; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { TrafficStats.setThreadStatsTag(request.getTrafficStatsTag()); } NetworkResponse networkResponse = mNetwork.performRequest(request); request.addMarker("network-http-complete"); if (networkResponse.notModified && request.hasHadResponseDelivered()) { request.finish("not-modified"); continue; } Response<?> response = request.parseNetworkResponse(networkResponse); request.addMarker("network-parse-complete"); if (request.shouldCache() && response.cacheEntry != null) { mCache.put(request.getCacheKey(), response.cacheEntry); request.addMarker("network-cache-written"); } request.markDelivered(); mDelivery.postResponse(request, response); } catch (VolleyError volleyError) { parseAndDeliverNetworkError(request, volleyError); } catch (Exception e) { VolleyLog.e(e, "Unhandled exception %s", e.toString()); mDelivery.postError(request, new VolleyError(e)); } } }
|
整个流程和缓存差不多,再来一个图:
Network
在上面的网络分发中看到了主要就是mNetwork.performRequest(request);
这句话执行了真正的网络请求操作,而Network
是一个接口,实现类是在创建RequestQueue
时候创建的BasicNetwork
,看看这个里面的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class BasicNetwork implements Network { @Override public NetworkResponse performRequest(Request<?> request) throws VolleyError { httpResponse = mHttpStack.performRequest(request, headers); networkResponse = new NetworkResponse(statusCode, responseContents,responseHeaders, false); } }
|
到现在请求的结果也回来了,那么具体是怎么去分发Response
的呢?主要是这句话mDelivery.postResponse(request, response);
而ResponseDelivery
是一个接口,实现类是创建RequestQueue
的时候创建的public class ExecutorDelivery implements ResponseDelivery
,看一下它的postResponse
方法,主要就是mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));
可以理解为向主线程发送了一个Runnable
而在这个Runnable
里面呢:
1 2 3 4 5
| if (mResponse.isSuccess()) { mRequest.deliverResponse(mResponse.result); } else { mRequest.deliverError(mResponse.error); }
|
第一个方法是不是就比较熟悉了,就是自定义Request
的时候要重写的两个方法之一,一般就直接mListener.onResponse(response);
就可以了,而错误的分发Request
基类已经实现完了。
到这,基本的过程差不多了,还有重试策略和缓存的具体没写,大概就这样吧。
参考:
详细解读Volley(五)—— 通过源码来分析业务流程
Volley 源码解析
Volley源码分析