Volley源码解析(三)
来源:互联网 发布:java 图形验证码 开源 编辑:程序博客网 时间:2024/05/20 18:51
在《Volley源码解析(一)》和《Volley源码解析(二)》中简单讲解了Volley的内部工作原理,一言以蔽之就是:创建请求Request对象,然后将请求对象放入队列RequestQueue中,开启线程NetworkDispatcher不断从线程中获取请求对象,然后执行请求并返回响应对象。具体的细节可参考上面两篇博文,在此不细说,关于Volley的使用可以参考其官方文档。
其实对于android来说,大部分网络请求的业务都是通过接口获取数据然后对UI进行渲染;对于Volley来说你可以在任意的线程(UI线程或者非UI线程)创建Request对象,但是通过NetworkDispatcher发起网络请求然后完成数据解析后,最终解析后的数据会传给UI线程(Main Thread)来使用。那么这个过程是怎么实现的呢?在NetWorkDispatcher这个thread的run方法的内部有如下一句代码(详见《Volley源码解析(二)》):
//主要是回调Listener接口,通知客户端获取数据 mDelivery.postResponse(request, response);
事实上这段代码就是将解析后的response对象交给客户端使用,确切的说是在将数据交给main thread使用,这个mDelivery是ResponseDelivery接口,其具体在Volley的具体体现是ExecutorDelivery。那么mDelivery是什么时候初始化的呢?
在初始化请求队列RequestQueue对象的时候会通过Volley.newRequestQueue(context)
几经辗转会调用:
public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); }
可以看出mDelivery变量的具体实例就是ExecutorDelivery,且该对象包含一个Handler对象,到此为止Volley的工作总体思路就不难猜出了:
1、异步线程发起网络请求
2、将请求包换的数据通过handler发送给main thread
这样就Volley就保证了获取网络数据回调更新UI界面过程,关于handler的工作机制可以参考博主的《android消息处理机制详解》
下面就看看ExecutorDelivery的post方法都作了写什么?
private final Executor mResponsePoster; public ExecutorDelivery(final Handler handler) { // Make an Executor that just wraps the handler. //该Executor只是将Runable经过hanler重新包装一下, mResponsePoster = new Executor() { @Override public void execute(Runnable command) { handler.post(command); } }; }
从上面代码来看ExecutorDelivery的作用就是将交给Executor对象的Runnable交给handler处理,所以现在就可以看看post方法都作了写什么:
@Override public void postResponse(Request<?> request, Response<?> response) { postResponse(request, response, null); } @Override public void postResponse(Request<?> request, Response<?> response, Runnable runnable) { mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); }
上面代码很简单,就是将ResponseDeliveryRunnable交给mResponsePoster这个Executor,最终交给handler处理。所以我们来看看ResponseDeliveryRunnable都作了写什么:
public void run() { //省略部分代码 if (mResponse.isSuccess()) { mRequest.deliverResponse(mResponse.result); } else { mRequest.deliverError(mResponse.error); } //省略部分代码 }
上面的逻辑也很简单,就是将回调相关接口来通知客户端网络返回结果,如果失败的话回调ErrorListener接口,将错误原因交给客户端,成功则交给Request对象的子类来处理(因为deliverResponse是一个抽象方法)。以StringRequest对象来举例,其deliverResponse方法实现如下:
@Override protected void deliverResponse(String response) { if (mListener != null) { mListener.onResponse(response); } }
所以如果如果以StringRequest请求对象对正确和错误的响应都感兴趣的话,可以如下构建StringRequest对象:
RequestQueue queue = Volley.newRequestQueue(this); String url = "http://www.baidu.com"; //请求成功的接口 Response.Listener<String> requestSuccessListener = new Response.Listener<String>() { @Override public void onResponse(String response) { Log.i("VolleryTest","请求成功"+response); } }; //请求失败的接口 Response.ErrorListener errorListener = new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.i("VolleryTest","请求失败"); error.printStackTrace(); } }; //构建请求对象:此处为get请求 StringRequest request = new StringRequest( url,requestSuccessListener,errorListener); queue.add(request);
运行上述代码发现打印请求失败,也就是说走了ErrorListener,并且Volley丢给我一个内部的log:
Unexpected response code 302
奇哉怪也,使用okhttp请求百度首页并没有出现这个错误,于是追踪其源码,在BasicNetWork这个类中找到类原因(这个类具体干嘛的,参考博主的其他两篇volley博客,在此不细说):
if (statusCode < 200 || statusCode > 299) { throw new IOException(); }
一目了然,Volley对于http的状态码作了判断,不满足200 =
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
所以从对状态码的处理来看,OKhttp的处理比Volley理智多了,并没有一棒子打死。
Volley对http方法的支持
我们知道http支持get,post,put,delete等方法,那么volley又是支持哪些http的方法呢?查看Request代码可以发现volley对常用的http方法都作了支持:
/** * Supported request methods. */ public interface Method { int DEPRECATED_GET_OR_POST = -1; int GET = 0; int POST = 1; int PUT = 2; int DELETE = 3; int HEAD = 4; int OPTIONS = 5; int TRACE = 6; int PATCH = 7; }
get请求不用说,下面来简单分析下post请求是怎么实现的,确切的收是分析post请求是怎么携带参数的。在HurlStack类中提供了一个setConnectionParametersForRequest方法:
static void setConnectionParametersForRequest(HttpURLConnection connection, Request<?> request) { switch (request.getMethod()) { case Method.POST: connection.setRequestMethod("POST"); addBodyIfExists(connection, request); break; } }
如果是post请求,则会调用addBodyIfExists方法来组建参数(如果有参数的话):
static void addBodyIfExists(HttpURLConnection connection, Request<?> request) { byte[] body = request.getBody(); //省略组建post参数的代码 }
addBodyIfExists的第一步是通过Request对象的getBody方法来获取post请求所需的参数,所以进度该方法看看是怎么回事儿:
public byte[] getBody(){ //通过getParams方法获取post请求参数 Map<String, String> params = getParams(); if (params != null && params.size() > 0) { return encodeParameters(params, getParamsEncoding()); } return null; }
简单明了,原来post,delete,等请求参数的构建是通过Request对象的getParams() 方法来实现的:
protected Map<String, String> getParams() { return null; }
该方法是一个protected方法,所以如果以StringReqeust 对象发起post请求的话,那么代码就该是如下所示 了:
new StringRequest(Request.Method.POST,url,requestSuccessListener,errorListener) { @Override protected Map<String, String> getParams() { Map<String,String> postParms = new HashMap<>(); postParms.put("xxx","xxxx"); return postParms; } };
不过看到这儿我总感觉怪怪的,本来是设置参数,提供的却是 getParams方法,而不是set方法,从设计上来说多少有点不合理的感觉。OKhttp对http请求方法的封装从代码设计角度来说就优雅的多了,OKhttp有点严格将请求和请求体分成两个对象Request和RequestBody,有点模仿html form表单请求的味道,想要了解更多的话可以参考《Okhttp发起http请求概述》
到此为止volley系列源码分析就结束了,至于volley的缓存因为其实现原理也很简单,在博主的volley系列中就不做具体解说了
- Volley源码解析(三)
- Volley源码解析(三)——图片加载
- Volley源码解析(三)——NetworkDispatcher
- Volley源码解析 --- Volley组成(1)
- 【Volley】Volley源码解析
- Volley源码解析<三> Request请求
- Volley源码解析(三)网络请求流程
- volley源码解析(三)--Volley核心之RequestQueue类
- Volley 源码解析(一)
- Volley 源码解析(二)
- Volley源码解析(一)
- Volley源码解析(二)
- Volley源码分析(三)
- Android应用层(网络编程)三(Volley使用与源码解析)
- Volley源码解析(二):RequestQueue
- Volley源码解析(一),基本概述
- volley源码解析
- Volley 源码解析
- servlet关于方法getServletConfig返回空指针
- 【C++程序设计】-初始C++对象
- vim插件: nerdcommenter[快速注释]
- Hive实战:将xml文件处理为txt文件,并用Hive进行微博数据分析
- (C语言版)链表(二)——实现单向循环链表创建、插入、删除、释放内存等简单操作
- Volley源码解析(三)
- 触发器和存储过程
- Scala(一)
- 【C++程序设计】-从结构到类的演变
- 序列化和反序列化
- 转载整理-shell脚本的基本知识
- 经验总结-DDMS出现:远程主机强迫关闭了一个现有的连接的解决办法
- 消除pycharm中的波浪线的办法
- 进程,线程,递归调用找所有文件的案例,反射