Volley现在大家想必都已经会是用了,光使用是不够的。我们还要弄清楚Volley整个的框架,开始我也是迷迷糊糊的以为会使用就可以了,但是毕竟安卓开源的吗 咱们要学习一下大神们的思想,这样也有助于咱们更好的理解Volley
盗用别人一张Volley框架图 Volley官方也有一张图 我感觉这个比较详细就拿过来了
我们看着这个图是不是感觉很乱,其实我们可以把这张图仔细的分为三部分来看
第一部分:main thread 主线程 (请求队列)
第二部分:cache thread 缓存线程
第三部分:网络线程
这样我们从头开始分析Volley ,我们知道Volley使用的时候第一行代码是Volley.newRequestQueue(context) 这样我们得到一个RequestQueue 我们看一下源代码
- public static RequestQueue newRequestQueue(Context context) {
- return newRequestQueue(context, null);
- }
- 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;
- }
好咱们看一下这个HttpStack
- public interface HttpStack {
- /**
- * Performs an HTTP request with the given parameters.
- *
- * <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise,
- * and the Content-Type header is set to request.getPostBodyContentType().</p>
- *
- * @param request the request to perform
- * @param additionalHeaders additional headers to be sent together with
- * {@link Request#getHeaders()}
- * @return the HTTP response
- */
- public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
- throws IOException, AuthFailureError;
- }
其实就是一个接口没什么神奇的 其实这个HttpStack对象才是真正的去网络拿回我们需要的数据 (题外话 我们定义自己的HttpStack 把这个作为传输层 这样就可以使用Volley+OkHttpClient 大家有时间去研究 不扯了 我就是顺便说一句)
好 我们不要纠结这个HttpStack 我们还是看上面这个newRequestQueue方法 我们看第10行 判断stack是不是null
- 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;
我们创建一个Network对象(NetWork也是一个接口) 在Volley中的实现类是BasicNetwork 我们可以看一下这个源码
- public interface Network {
- /**
- * Performs the specified request.
- * @param request Request to process
- * @return A {@link NetworkResponse} with data and caching metadata; will never be null
- * @throws VolleyError on errors
- */
- public NetworkResponse performRequest(Request<?> request) throws VolleyError;
- }
还是看我们上一段代码我们new了一个RequestQueue紧接着调用了它的start方法 好我们就看一下start方法
- public void start() {
- stop(); // Make sure any currently running dispatchers are stopped.
- // Create the cache dispatcher and start it.
- mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
- mCacheDispatcher.start();
- // Create network dispatchers (and corresponding threads) up to the pool size.
- for (int i = 0; i < mDispatchers.length; i++) {
- NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
- mCache, mDelivery);
- mDispatchers[i] = networkDispatcher;
- networkDispatcher.start();
- }
- }
- 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.
- if (!request.shouldCache()) {
- mNetworkQueue.add(request);
- return request;
- }
- // 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<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;
- }
- }
- public class CacheDispatcher extends Thread {
- ……
- @Override
- public void run() {
- if (DEBUG) VolleyLog.v("start new dispatcher");
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- // Make a blocking call to initialize the cache.
- mCache.initialize();
- while (true) {
- try {
- // Get a request from the cache triage queue, blocking until
- // at least one is available.
- final Request<?> request = mCacheQueue.take();
- request.addMarker("cache-queue-take");
- // If the request has been canceled, don't bother dispatching it.
- if (request.isCanceled()) {
- request.finish("cache-discard-canceled");
- continue;
- }
- // Attempt to retrieve this item from cache.
- Cache.Entry entry = mCache.get(request.getCacheKey());
- if (entry == null) {
- request.addMarker("cache-miss");
- // Cache miss; send off to the network dispatcher.
- mNetworkQueue.put(request);
- continue;
- }
- // If it is completely expired, just send it to the network.
- if (entry.isExpired()) {
- request.addMarker("cache-hit-expired");
- request.setCacheEntry(entry);
- mNetworkQueue.put(request);
- continue;
- }
- // We have a cache hit; parse its data for delivery back to the request.
- request.addMarker("cache-hit");
- Response<?> response = request.parseNetworkResponse(
- new NetworkResponse(entry.data, entry.responseHeaders));
- request.addMarker("cache-hit-parsed");
- if (!entry.refreshNeeded()) {
- // Completely unexpired cache hit. Just deliver the response.
- mDelivery.postResponse(request, response);
- } else {
- // Soft-expired cache hit. We can deliver the cached response,
- // but we need to also send the request to the network for
- // refreshing.
- request.addMarker("cache-hit-refresh-needed");
- request.setCacheEntry(entry);
- // Mark the response as intermediate.
- response.intermediate = true;
- // Post the intermediate response back to the user and have
- // the delivery then forward the request along to the network.
- mDelivery.postResponse(request, response, new Runnable() {
- @Override
- public void run() {
- try {
- mNetworkQueue.put(request);
- } catch (InterruptedException e) {
- // Not much we can do about this.
- }
- }
- });
- }
- } catch (InterruptedException e) {
- // We may have been interrupted because it was time to quit.
- if (mQuit) {
- return;
- }
- continue;
- }
- }
- }
- }
- ublic class NetworkDispatcher extends Thread {
- ……
- @Override
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- Request<?> request;
- while (true) {
- try {
- // Take a request from the queue.
- request = mQueue.take();
- } catch (InterruptedException e) {
- // We may have been interrupted because it was time to quit.
- if (mQuit) {
- return;
- }
- continue;
- }
- try {
- request.addMarker("network-queue-take");
- // If the request was cancelled already, do not perform the
- // network request.
- if (request.isCanceled()) {
- request.finish("network-discard-cancelled");
- continue;
- }
- addTrafficStatsTag(request);
- // Perform the network request.
- NetworkResponse networkResponse = mNetwork.performRequest(request);
- request.addMarker("network-http-complete");
- // If the server returned 304 AND we delivered a response already,
- // we're done -- don't deliver a second identical response.
- if (networkResponse.notModified && request.hasHadResponseDelivered()) {
- request.finish("not-modified");
- continue;
- }
- // Parse the response here on the worker thread.
- 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);
- } catch (VolleyError volleyError) {
- parseAndDeliverNetworkError(request, volleyError);
- } catch (Exception e) {
- VolleyLog.e(e, "Unhandled exception %s", e.toString());
- mDelivery.postError(request, new VolleyError(e));
- }
- }
- }
- }
我们看一下postResponse方法
- public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
- request.markDelivered();
- request.addMarker("post-response");
- mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
- }
我们调用了execute方法 这里有个参数ResponseDeliveryRunnable 我们看一下这个源码
- private class ResponseDeliveryRunnable implements Runnable {
- private final Request mRequest;
- private final Response mResponse;
- private final Runnable mRunnable;
- public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
- mRequest = request;
- mResponse = response;
- mRunnable = runnable;
- }
- @SuppressWarnings("unchecked")
- @Override
- public void run() {
- // If this request has canceled, finish it and don't deliver.
- if (mRequest.isCanceled()) {
- mRequest.finish("canceled-at-delivery");
- return;
- }
- // Deliver a normal response or error, depending.
- if (mResponse.isSuccess()) {
- mRequest.deliverResponse(mResponse.result);
- } else {
- mRequest.deliverError(mResponse.error);
- }
- // If this is an intermediate response, add a marker, otherwise we're done
- // and the request can be finished.
- if (mResponse.intermediate) {
- mRequest.addMarker("intermediate-response");
- } else {
- mRequest.finish("done");
- }
- // If we have been provided a post-delivery runnable, run it.
- if (mRunnable != null) {
- mRunnable.run();
- }
- }
- }
我们看21行 deliverResponse这个方法是不是很熟悉 ,没错就是我们自定义Request必须实现的第二个方法 每一条
网络请求的回调都是回调到这个方法 ,最后我们再在这个方法中将响应的数据回调到Response.Listener的onResponse()方法中就可以了。
好了 整个volley框架的源码咱们就分析完了 是不是现在看晕了 我建议大家多看几遍(我当时看这个源码看了3天
笨鸟先飞嘛。。。) 书读百遍吗 你懂得
最后我们还是总结一下吧
我们首先在主线程中调用RequestQueue的add方法添加一条网络请求 然后我们把这条请求放到缓存队列 如果发现在
缓存中可以找到对应的请求的结果 我们就解析并且回调主线程就可以了 如果没有发现结果或者结果为null 我们就需要
把这条请求放到网络队列中 然后发送Http请求 再然后就是解析响应结果 写入缓存 并且回调主线程
这就是一个完整的Volley请求 现在看最上面的图是不是很简单了。。。