时间:2021-05-21
过去在Android上网络通信都是使用的Xutils 因为用它可以顺道处理了图片和网络这两个方面,后来发觉Xutils里面使用的是HttpClient 而Google在6.0的版本上已经把HttpClient废除了,所以开始寻找新的网络框架,okhttp也用过,但是它是在作用在UI线程,使用起来还需要用handler 所以就先用着Volley框架了。 这里我先分析下Volley框架的简单网络请求的源码。
使用Volley请求网络数据的简单过程:
RequestQueue queue = Volley.newRequestQueue(this); //实例化一个请求队列 Google推荐写一个单例类 获取唯一一个队列 StringRequest request = new StringRequest(Request.Method.POST, url1, new Response.Listener<String>() { @Override public void onResponse(String response) { Toast.makeText(MainActivity.this, "success"+response, Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Toast.makeText(MainActivity.this, "失败了"+error.getMessage(), Toast.LENGTH_SHORT).show(); } }){ @Override protected Map<String, String> getParams() throws AuthFailureError { //重写这个函数提交参数 也可以重写一个Request实现这个方法 Map<String,String> params = new HashMap<>(); params.put(aaa+"name","1233555"); //参数 return params; } }; queue.add(request);请求的处理在newRequestQueue的时候就开始执行了 只不过那时候请求队列中还没有请求 所以阻塞了 当 add的方法执行时 才开始真正请求网络
所以我们先来看 queue.add(request) 方法
分析add方法 首先加入到mCurrentRequests集合中 这个集合存放所有这个队列所处理的请求 然后判断这个请求是否需要缓存,如果不需要缓存,那么直接加入mNetworkQueue队列中等待处理即可,如果需要那么最终加入到mCacheQueue队列中,因为RequestQueue在处理请求时总会先处理缓存的任务,在处理缓存时如果第一次处理没有缓存还是会加入mNetworkQueue队列中处理,如果有缓存那么就直接获取缓存了,之后判断当前的请求中是否有相同的请求,如果有的话那么就把这个请求加入到暂存集合中,如果没有那么就加入一个空的到请求到暂存队列中,用来以后判断是否有和这个请求相同的请求,然后加入缓存队列中即可。
然后我们来看RequstQueue的创建过程
RequestQueue的创建过程也比较简单 根据sdk版本号判断使用HttpURLConnection还是HttpClient 因为在2.3之前 httpUrlConnection有一个重大的bug 所以使用HttpClient代替,而httpUrlConnection体积小 支持gzip压缩和缓存,并且速度相对httpClient快 并逐渐优化 所以选择httpUrlConnection 之后根据创建的NetWork 创建RequestQueue队列 然后开启即可
之后我们查看 queue的start方法
这个方法 先执行缓存调度器线程然后执行4个网络工作调度器线程,因为在缓存调度器中 会判断是否缓存过,如果缓存过并且没过期,就直接复用缓存的,不把任务加入netWordQueue中 所以下面的NetWork调度器线程就会取不到请求而阻塞,不会执行,而如果没有缓存,缓存调度器线程中就会把请求加入NetWork队列中,下面的netWork调度器就会取到该请求并执行了
我们仔细看一下CacheDispatcher线程的源码:
run方法的代码比较长 我们分开来看 先看第一部分:
@Override public void run() { if (DEBUG) VolleyLog.v("start new dispatcher"); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //设置线程的优先级 值为10 // 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"); //添加缓存miss标记 // Cache miss; send off to the network dispatcher. mNetworkQueue.put(request); //换区缓存失败 添加到netWork中等待请求 continue; } // If it is completely expired, just send it to the network. if (entry.isExpired()) { //判断缓存是否过期了 如果过期了 那么就添加到netWork中等待请求 request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); mNetworkQueue.put(request); continue; }第二部分 :
上面代码的具体过程也很简单 首先从缓存请求队列取出一个请求,在缓存中看看有没有该请求的缓存,如果没有 那么 请求放入NetWork调度器中 等待调用 如果有 也分几种情况 如果获取到的是空,放入NetWOrk 如果过期 放入 NetWork 如果不需要刷新 就直接从缓存获取响应信息并解析 然后用mDelivery回调接口即可 如果需要刷新 放入NetWOrd队列等待调用。。。
我们再来看看NetworkDispatcher 线程的代码就可以了 类似于CacheDispatcher的代码:
@Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //设置优先级 10 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); //回调错误接口 } } }NetworkDispatcher 线程的执行过程 先从 networkDispatch中获取一个请求 然后判断 是否取消了 如果没有 那么就执行NetWOrk的performRequest方法 执行http请求,这个函数内部才是真正的请求数据 ,请求后 根据设置的shouldCache标志 判断是否放入缓存中 之后回调一些接口方法 即可 这样就完成了一个请求
最后我们看一看NetWork类mNetwork.performRequest(request)方法是如何提交请求的吧 代码比较长 但是不难:
@Override public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); //记录开始时间 while (true) { HttpResponse httpResponse = null; byte[] responseContents = null; Map<String, String> responseHeaders = Collections.emptyMap(); //初始化响应头为空 try { // Gather headers. Map<String, String> headers = new HashMap<String, String>(); //请求头 addCacheHeaders(headers, request.getCacheEntry()); //根据缓存添加请求头 httpResponse = mHttpStack.performRequest(request, headers); //调用HttpStack的方法请求网络 StatusLine statusLine = httpResponse.getStatusLine(); int statusCode = statusLine.getStatusCode(); responseHeaders = convertHeaders(httpResponse.getAllHeaders()); //获取响应头 // Handle cache validation. if (statusCode == HttpStatus.SC_NOT_MODIFIED) { //如果为304 读取的缓存 Entry entry = request.getCacheEntry(); //查看以前是否缓存过 if (entry == null) { //如果以前缓存的为空 那么 说明上次缓存的请求也为空 直接返回response return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // A HTTP 304 response does not have all header fields. We // have to use the header fields from the cache entry plus // the new ones from the response. // http://WorkQueue 等待调用以上就是本文的全部内容,希望对大家学习Android Volley框架有所帮助。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
Android使用volley过程中遇到的问题解决办法本文主要介绍使用volley过程中遇到的问题,错误提示:com.android.volley.NoConn
Android中Volley二次封装并实现网络请求缓存Android目前很多同学使用Volley请求网络数据,但是Volley没有对请求过得数据进行缓存,因此需
Android网络请求框架Volley实例详解首先上效果图Logcat日志信息onReponseVolley特别适合数据量不大但是通信频繁的场景,像文件上传下载
Volley现在已经被官方放到AOSP里面,已经逐步成为Android官方推荐的网络框架。类抽象对Http协议的抽象Requeset顾名思义,对请求的封装,实现
使用volley进行网络请求:需先将volley包导入androidstudio中File下的ProjectStructrue,点加号导包volley网络请求步