首页 > 学院 > 开发设计 > 正文

Volley源码解析

2019-11-09 17:44:09
字体:
来源:转载
供稿:网友

Volley是Google开发的一个网络请求框架,该框架适合进行小而频繁的网络请求。 Volley的使用比较简单,只需几个简单的操作就可以实现发送请求。以StringRequest 为例:

//创建一个请求队列RequestQueue requestQueue = Volley.newRequestQueue(this); String url = "request_url"; //创建StringRequest对象,以Post数据为例 StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() { @Override public void onResponse(String response) { Log.i("TAG", response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.i("TAG", error.toString()); } }) { //填写需要post的表单 @Override PRotected Map<String, String> getParams() throws AuthFailureError { HashMap<String, String> map = new HashMap<>(); map.put("userId", "0"); //测试数据 map.put("sessionId", "0"); return map; } };requestQueue.add(request);

首先需要看看 Volley.newRequestQueue(this) 这句是如何实现的:

public static RequestQueue newRequestQueue(Context context, HttpStack stack) { //缓存路径 File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); //代码省略 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; }

这里需要关注的是当SDK版本小于9时,就会使用HttpClientStack来完成请求,否则,则用HurlStack。前者使用的是HttpClient,而后者使用的是HttpURLConnection。 接着,执行了queue.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(); } }

上述代码中出现了两个分发器:CacheDispatcher和NetworkDispatcher。它们都是继承Thread,分别用于处理缓存和网络请求。其中处理网络请求的线程有4个。

private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;

既然是线程的子类,并且都调用了start方法启动线程,那么就需要看看run方法是如何实现的:

CacheDispatcher

@Override public void run() { //代码省略 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.addMarker("cache-hit-refresh-needed"); 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; } } }

NetworkDispatcher

public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); while (true) { long startTimeMs = SystemClock.elapsedRealtime(); Request<?> request; 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; } addTrafficStatsTag(request); // 执行网络请求,mNetwork就是之前创建队列时的BasicNetwork,里面具体实现了网络请求 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) { volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); parseAndDeliverNetworkError(request, volleyError); } catch (Exception e) { VolleyLog.e(e, "Unhandled exception %s", e.toString()); VolleyError volleyError = new VolleyError(e); volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); mDelivery.postError(request, volleyError); } }}

接着需要看看请求结果是如何被回调的: mDelivery.postResponse(request, response),其实是调用了ExecutorDelivery中的postResponse方法:

@Override public void postResponse(Request<?> request, Response<?> response, Runnable runnable) { request.markDelivered(); request.addMarker("post-response"); //线程池添加任务 mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); }

再看看该任务中的run方法:

@Override public void run() { if (mRequest.isCanceled()) { mRequest.finish("canceled-at-delivery"); return; } if (mResponse.isSuccess()) { //此处会调用Request的onResponse方法,实现回调 mRequest.deliverResponse(mResponse.result); } else { mRequest.deliverError(mResponse.error); } if (mResponse.intermediate) { mRequest.addMarker("intermediate-response"); } else { mRequest.finish("done"); } if (mRunnable != null) { mRunnable.run(); } }

至此,对于网络请求是如何处理的有了一定的了解。紧接着看看每次添加网络请求是如何实现的,即add方法:

public <T> Request<T> add(Request<T> 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; } // 否则,添加到缓存中,该缓存的键值对为cacheKey和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); if (VolleyLog.DEBUG) { VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey); } } else { //没有对应request就设置为null mWaitingRequests.put(cacheKey, null); //添加到处理缓存队列 mCacheQueue.add(request); } return request; } }
上一篇:const 的作用?

下一篇:2017面试要点

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表