网络一直是我我的的盲点,前一阵子抽空学习了一下Volley网络工具的用法,也透过源代码进行了进一步的学习,有一些心得想分享出来。在Android开发中,成熟的网络工具很多,Android自带了HttpClient。还有okhttp,还有koush大神建立的ion开源项目,而后就是google后来增长到Android项目源代码中的Volley。html
为何使用Volley,是因为Volley使用简单,逻辑清晰,即便在调试过程当中出现了问题。也可以高速的经过源代码进行定位。java
因为已经习惯了使用Gradle构架应用。因此我在第一次想要使用Volley的时候尝试寻找可否够经过gradle的配置文件进行库依赖。惋惜的是,并无。但即便这样Volley的库也很是easy作出来增长到咱们的project中。android
首先需要ant编译工具,而后假设有Android系统源代码的话,Volley在frameworks/volley文件夹下。git
假设没有Android源代码,也很是好办,可以单独从Android的仓储中克隆出Volley源代码:github
git clone https://android.googlesource.com/platform/frameworks/volley不幸的是,volley库的源代码Android并无托管在其在Github的账号上,因此仅仅能在googlesource上进行克隆,固然在国内也就需要先FQ才干够了。
下图为Volley源代码结构:数据库
克隆成功后。可以方便的使用ant进行编译,固然,假设是在完整的Android源代码下,也可以直接经过make进行编译,但是时间一定会长很是多。这里使用ant编译为例,运行:json
ant jar结果如图所看到的:
这样jar包就生成了,很是方便吧,接下来将其加入到project中就可以使用了。
api
Volley的网络请求父类为Request<T>。可以提供给开发人员进行继承。同一时候也预置了几种开发中常用的请求类型。下边介绍两个:StringRequest和JsonObjectRequest。cookie
为了更加贴近实际使用,下边将使用Volley与Cloudant进行通信作演示样例。网络
Cloudant是一家提供云服务业务的公司。其向开发人员提供免费的云存储、云数据库服务。关于其注冊等流程本文不作叙述,很是easy的。
直接从登陆開始:
Volley的一个很是大的特点。就是所有的网络请求无需开发人员本身运行,而是在请求构造完毕后扔到Volley的请求队列中,队列依次进行请求,这样就省去了很是多麻烦。开发人员也不用操心网络请求是否会冲突。是否会在主线程,这些烦心事Volley的网络队列都帮咱们攻克了。
通常来讲,一个应用程序假设网络请求没有特别频繁则全然可以仅仅有一个请求队列(相应Application),假设许多或其它状况,则可以是一个Activity相应一个网络请求队列,详细状况详细分析。
下边的代码展现了怎样申请一个Volley网络请求队列:
RequestQueue mQueue; mQueue = Volley.newRequestQueue(getApplicationContext());
这样就成功申请了一个网络请求队列,假设仅仅有一个,则可以在Application中进行申请。
若是已经成功注冊。登陆名foo。passwordbar。
经过查阅Cloudant的登陆认证文档:https://docs.cloudant.com/api/authn.html。
可以发现Cloudant登陆认证相关接口有三个:
这里咱们使用POST方法进行cookie登陆认证。结合上边若是的username和password可知:
要訪问的url为 foo.cloudant.com/_session 头信息为 Content-Type: application/x-www-form-urlencoded 參数为 name = foo, password = bar
若訪问成功,咱们就可以在网络回应中获取cookie,以备以后其它操做使用。显然,这个请求跟json毫无关系。应该使用StringRequest。StringRequest有两种构造方法:
public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) public StringRequest(String url, Listener<String> listener, ErrorListener errorListener)第二个方法仅仅有GET请求才干够使用,第一个方法的method參数可以用来本身定义请求类型,这里咱们需要的是POST,因此应该使用第一个构造方法:
StringRequest request = new StringRequest( Request.Method.POST, "http://foo.cloudant.com/_session", new Response.Listener<String>() { @Override public void onResponse(String s) { //收到成功应答后会触发这里 } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { //出现链接错误会触发这里 } } );
上边的代码中,咱们成功构造了一个StringRequest,当中已经包括了咱们需要的POST和正确的URL,同一时候还加入了网络回应监听器。但是,还缺乏文档要求咱们的头信息和參数。StringRequest在构造中并不提供这些信息的定义,这也是与其它常用网络工具不一样的地方,刚接触的同窗可能会很是不适用,经过复写StringRequest的两个方法就可以将这些信息放进去了。下边来无缺这个请求:
StringRequest request = new StringRequest( Request.Method.POST, "http://foo.cloudant.com/_session", new Response.Listener<String>() { @Override public void onResponse(String s) { } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { } } ) { @Override public Map<String, String> getHeaders() throws AuthFailureError { //设置头信息 Map<String, String> map = new HashMap<String, String>(); map.put("Content-Type", "application/x-www-form-urldecoded"); return map; } @Override protected Map<String, String> getParams() throws AuthFailureError { //设置參数 Map<String, String> map = new HashMap<String, String>(); map.put("name", "foo"); map.put("password", "bar"); return map; } };
相比第一次咱们的构造过程,这一次多了两个复写的方法来设置头信息和參数,很是easy吧。这个时候请求基本完毕了,但是却缺乏还有一个很是重要的东西。咱们的登陆认证为的是拿回属于本身的cookie,假设不能获取cookie的话,多么正确的请求格式都是白费力气啊。想要拿到cookie同样也是经过复写还有一个方法进行获取:
@Override protected Response<String> parseNetworkResponse(NetworkResponse response) { for (String s : response.headers.keySet()) { if (s.contains("Set-Cookie")) { mCookie = response.headers.get(s); break; } } return super.parseNetworkResponse(response); }在网络请求成功后。服务端返回应答信息。而咱们所需的Cookie信息就在这些应答信息中,经过相应答信息的遍历查找。很是方便就可以找到咱们所需的信息了。
到这里,咱们的登陆认证请求就构造完毕了,最后需要作的就是将这个StringRequest扔到咱们的请求队列中去:
mQueue.add(request);网络通畅的状况下。很是快就行获取Cookie信息了。
在注冊Cloudant成功后,Cloudant会在咱们的账号中建立一个默认数据库——crud,当中保存着一行測试数据welcome。
让咱们用Volley来訪问这条数据。查阅Cloudant API文档Documents相关可以发现:
经过简单的GET请求搭配正确的URL就能够获得文件(数据)内容。固然。这一切的前提是咱们已经掌握了正确的Cookie数据。那么,咱们需要:
1. 请求头数据中包括正确的Cookie信息 2. 訪问正确的URL 3. 请求类型:GET若是经过上一步登录认证后咱们将Cookie信息保存在了mCookie字符串变量中。
而咱们需要訪问的URL经过查阅文档也可以得出路径为 数据库名 + 文档名,即foo.cloudant.com/crud/welcome。
万事俱备。使用StringRequest:
StringRequest request = new StringRequest( "http://foo.cloudant.com/crud/welcome", new Response.Listener<String>() { @Override public void onResponse(String s) { } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { } } ) { @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); map.put("Cookie", mCookie); return map; } }; mQueue.add(request);
简单的网络请求StringRequest全然处理得来。使用也比較简单,就介绍到这里。
下边介绍JsonObjectRequest应用方法。
public JsonObjectRequest(int method, String url, JSONObject jsonRequest, Listener<JSONObject> listener, ErrorListener errorListener) public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener, ErrorListener errorListener)第一种方法參数以此为:请求方法,訪问的URL,Json数据对象,请求成功监听器,请求失败监听器。
下边以POST方式建立数据为例,经过查看Cloudant文档,可知:
1. 訪问的URL path为数据库文件夹 2. Content-Type被要求为application/json 3. 携带的数据要求为json数据
既然方法要求为POST,咱们又是建立数据。确定数据内容不会为空,因此咱们选择另一种构造方法。首先,建立一个Json对象:
JSONObject jsonObject = new JSONObject(); jsonObject.put("_id", "testinfo"); jsonObject.put("person", "foo"); jsonObject.put("phone", "bar");
JsonObjectRequest request = new JsonObjectRequest( "http://foo.cloudant.com/crud", jsonObject, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject jsonObject) { } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { } } ) { @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); map.put("Cookie", mCookie); return map; } }; mQueue.add(request);
最后。将构造完毕的请求丢进队列中。由Volley进行调度处理。这个时候最好仍是再回头看一看以前分析的请求所需要哪些元素,不难发现。Volley的json请求中。并无对Content-Type进行特殊设定。JsonObjectRequest是继承于JsonRequest的。而JsonRequest已经帮咱们完毕了这个动做:
@Override public String getBodyContentType() { return PROTOCOL_CONTENT_TYPE; }
/** Charset for request. */ private static final String PROTOCOL_CHARSET = "utf-8"; /** Content type for request. */ private static final String PROTOCOL_CONTENT_TYPE = String.format("application/json; charset=%s", PROTOCOL_CHARSET);
关于Volley和Cloudant不少其它的通讯细节,见CloudantVolley项目:https://github.com/airk000/CloudantVolley