Volley net
来源:互联网 发布:手机音频合成软件 编辑:程序博客网 时间:2024/04/30 05:19
如同上一篇学习的过程:
也从请求开始顺藤摸瓜:由于volley是不支持大文件操作的我们只看get和post请求;
get请求:
post请求:
<span style="white-space:pre"></span>private void postMethod() {JsonObjectRequest jsonRequest=new JsonObjectRequest(Method.POST, "url", null, new MyListener(), new MyVolleyErrorListener());mQueue.add(jsonRequest);}public class MyVolleyErrorListener implements com.ysheluo.volley.volley.Response.ErrorListener{@Overridepublic void onErrorResponse(VolleyError error) {}}public class MyListener implements Listener<org.json.JSONObject>{@Overridepublic void onResponse(JSONObject response) {}}一次post请求就已经完成十分的方便,追根溯源,我们先去看Volley.newRequestQueue(this); 到底做了什么,为什么仅仅是把一个request添加到里面就会去执行:
newRequestQueue有四个重载方法:最终调用的是:
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) { 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 { // 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); RequestQueue queue; if (maxDiskCacheBytes <= -1) { // No maximum size specified queue = new RequestQueue(new DiskBasedCache(cacheDir), network); } else { // Disk cache size specified queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network); } queue.start(); return queue; }首先是在cachedir中创建了一个名为volley的缓存文件:
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
然后根据安卓版本进行了判别,当版本在9以上使用了HttpURLConnection而以下使用了HttpClient
<span style="white-space:pre"></span>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);
默认情况下我们不指定缓存大小是会执行,默认大小是5M
queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
这里进行了默认的配置:
/** Number of network request dispatcher threads to start. */
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
即volley默认初始线程池中维持的线程为4
然后进行queue.start()
/** * Starts the dispatchers in this queue. */ 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的start方法,二者均是thread的子类;这里先是创建了一个CacheDispatcher的实例,然后调用了它的start()方法,接着在一个for循环里去创建NetworkDispatcher的实例,并分别调用它们的start()方法。这里的CacheDispatcher和NetworkDispatcher都是继承自Thread的,而默认情况下for循环会执行四次,也就是说当调用了Volley.newRequestQueue(context)之后,就会有五个线程一直在后台运行,不断等待网络请求的到来, 其中 CacheDispatcher是缓存线程,也就是当访问在极短的时间内volley会调用本地缓存的数据直接返回,置于这个缓存有效的时间,还需要往下面看,看他是什么情况下将request标记为缓存有效,以及什么时候缓存过期的;NetworkDispatcher是网络请求线程。调用
mCacheDispatcher.start();也就是执行其run方法,我们看run方法里面是怎么进行操作的:
@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; } } }而我们看RequestQueue的add(Request<T> request)方法
request.setRequestQueue(this); synchronized (mCurrentRequests) { mCurrentRequests.add(request); }<span style="white-space:pre"></span>
mCurrentRequests是一个HashSet
接下来是:
// If the request is uncacheable, skip the cache queue and go straight to the network.
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
如果这个请求不允许缓存那么就直接添加到mNetworkQueue里面并返回request;
如果允许(默认情况下是true)就获取cachekey值
<span style="white-space:pre"></span>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); }检查存放requestqueue的mWaitingRequests是否包含该cache值,然后如果有的话就取出对应的含有该请求的列表,因为可能是多次请求的,所以volley建立一个linkedlist进行维持,当不存在时放一个key为cachekey,value值为null的,用来标识有这个缓存请求了。
那么volley是怎么设定缓存的作用范围呢?即缓存策略呢:就反过来查看NetworkDispatcher的run方法:
<span style="white-space:pre"></span>Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); while (true) { long startTimeMs = SystemClock.elapsedRealtime(); Request<?> request; 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) { 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); } }
可以看出其中去连接网络去请求的方法是:mNetwork.performRequest(request);mNetwork是创建RequestQueue时的Network network = new BasicNetwork(stack);,真正指向的是子类BasicNetWork,追踪朔源,查看它的performRequest(request)方法:
其中核心是也就是真正去请求网络的方法: mHttpStack.performRequest(request, headers);
由于安卓6.0已经移除httpclient故这里仅查看HttpUrlClient,也就是主要关注 HurlStack类;查看其performRequest方法:
@Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { String url = request.getUrl(); HashMap<String, String> map = new HashMap<String, String>(); map.putAll(request.getHeaders()); map.putAll(additionalHeaders); if (mUrlRewriter != null) { String rewritten = mUrlRewriter.rewriteUrl(url); if (rewritten == null) { throw new IOException("URL blocked by rewriter: " + url); } url = rewritten; } URL parsedUrl = new URL(url); HttpURLConnection connection = openConnection(parsedUrl, request); for (String headerName : map.keySet()) { connection.addRequestProperty(headerName, map.get(headerName)); } setConnectionParametersForRequest(connection, request); // Initialize HttpResponse with data from the HttpURLConnection. ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1); int responseCode = connection.getResponseCode(); if (responseCode == -1) { // -1 is returned by getResponseCode() if the response code could not be retrieved. // Signal to the caller that something was wrong with the connection. throw new IOException("Could not retrieve response code from HttpUrlConnection."); } StatusLine responseStatus = new BasicStatusLine(protocolVersion, connection.getResponseCode(), connection.getResponseMessage()); BasicHttpResponse response = new BasicHttpResponse(responseStatus); response.setEntity(entityFromConnection(connection)); for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) { if (header.getKey() != null) { Header h = new BasicHeader(header.getKey(), header.getValue().get(0)); response.addHeader(h); } } return response; }
这里volley请求大致流程就结束了。
- Volley net
- Volley
- Volley
- volley
- volley
- Volley
- Volley
- volley
- Volley
- Volley
- volley
- Volley
- volley
- Volley
- Volley
- Volley
- volley
- Volley
- CCF 最优灌溉
- Encryto Message
- Nginx的命令行控制-转自《深入理解Nginx模块开发与架构解析》第2版
- hdu 1556 color the balls
- JS笔记:局部变量与全局变量
- Volley net
- mysqli stmt 预处理的作用
- 【BZOJ3294】[Cqoi2011]放棋子【计数DP】
- python提取知乎首页问答的url
- 第7周-项目1-成员函数、友元函数和一般函数有区别
- Cocos2d-x 3.9教程:10.使用CocosStudio的UI编辑器从UI文件中加载布局和控件
- 面试问题--数据安全分析师
- UVA699(树)
- Dialog中使用handler时报:Can't create handler inside thread that has not called Looper.prepare()