引言

网络一直是我个人的盲点,前一阵子抽空学习了一下Volley网络工具的用法,也透过源代码进行了进一步的学习,有一些心得想分享出来。在Android开发中,成熟的网络工具不少,Android自带了HttpClient。还有okhttp,还有koush大神创建的ion开源项目,然后就是google后来增加到Android项目源代码中的Volley。

为什么使用Volley,是由于Volley使用简单,逻辑清晰,即使在调试过程中出现了问题。也能够高速的通过源代码进行定位。

Volley编译

由于已经习惯了使用Gradle构架应用。所以我在第一次想要使用Volley的时候尝试寻找能否够通过gradle的配置文件进行库依赖。可惜的是,并没有。但即使这样Volley的库也非常easy做出来增加到我们的project中。

首先须要ant编译工具,然后假设有Android系统源代码的话,Volley在frameworks/volley文件夹下。

假设没有Android源代码,也非常好办,能够单独从Android的仓储中克隆出Volley源代码:

git clone https://android.googlesource.com/platform/frameworks/volley

不幸的是,volley库的源代码Android并没有托管在其在Github的帐号上,所以仅仅能在googlesource上进行克隆,当然在国内也就须要先FQ才干够了。

下图为Volley源代码结构:

克隆成功后。能够方便的使用ant进行编译,当然,假设是在完整的Android源代码下,也能够直接通过make进行编译,可是时间必定会长非常多。这里使用ant编译为例,运行:

ant jar

结果如图所看到的:

这样jar包就生成了,非常方便吧,接下来将其加入到project中就能够使用了。

Volley使用

Volley的网络请求父类为Request<T>。能够提供给开发人员进行继承。同一时候也预置了几种开发中经常使用的请求类型。下边介绍两个:StringRequest和JsonObjectRequest。

为了更加贴近实际使用,下边将使用Volley与Cloudant进行通讯做演示样例。

Cloudant是一家提供云服务业务的公司。其向开发人员提供免费的云存储、云数据库服务。关于其注冊等流程本文不做叙述,非常easy的。

直接从登录開始:

1. 申请网络请求队列

Volley的一个非常大的特色。就是全部的网络请求无需开发人员自己运行,而是在请求构造完毕后扔到Volley的请求队列中,队列依次进行请求,这样就省去了非常多麻烦。开发人员也不用操心网络请求是否会冲突。是否会在主线程,这些烦心事Volley的网络队列都帮我们攻克了。

一般来说,一个应用程序假设网络请求没有特别频繁则全然能够仅仅有一个请求队列(相应Application),假设许多或其它情况,则能够是一个Activity相应一个网络请求队列,详细情况详细分析。

下边的代码展示了怎样申请一个Volley网络请求队列:

RequestQueue mQueue;
mQueue = Volley.newRequestQueue(getApplicationContext());

这样就成功申请了一个网络请求队列,假设仅仅有一个,则能够在Application中进行申请。

2. 使用Volley登录Cloudant

如果已经成功注冊。登录名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信息了。

3. 查看測试文档

在注冊Cloudant成功后,Cloudant会在我们的帐号中创建一个默认数据库——crud,当中保存着一行測试数据welcome。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWlyazAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

让我们用Volley来訪问这条数据。查阅Cloudant API文档Documents相关能够发现:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWlyazAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

通过简单的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);

在onResponse中我们会收到welcome这条数据的json形式字符串:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWlyazAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" style="font-size:12px">

简单的网络请求StringRequest全然处理得来。使用也比較简单,就介绍到这里。

下边介绍JsonObjectRequest应用方法。

4. 使用JsonObjectRequest创建新数据


首先看一下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数据对象,请求成功监听器,请求失败监听器。

另外一种构造方法中。若jsonRequest为空,则方法自己主动为GET。不为空则自己主动切换为POST。其它參数含义同样。


Cloudant的文档(https://docs.cloudant.com/api/documents.html)要求创建文档能够使用POST或PUT方法进行。所携带的数据均为json格式。这样以来,StringRequest就显得力不从心了,我们须要使用到Volley的还有一个自带请求类型:JsonObjectRequest。

下边以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");

在Cloudant数据存储系统中,id能够由开发人员指定。接下来进行JsonObjectRequest的构造和请求:

        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);

jsonObject数据不为空,所以请求方式自己主动切换为POST,url为所要创建数据所在的数据库所在路径。然后就是请求结果的监听器,最后别忘了将Cookie带上。否则会出现认证错误的。

最后。将构造完毕的请求丢进队列中。由Volley进行调度处理。这个时候最好还是再回头看一看之前分析的请求所须要哪些元素,不难发现。Volley的json请求中。并没有对Content-Type进行特殊设定。JsonObjectRequest是继承于JsonRequest的。而JsonRequest已经帮我们完毕了这个动作:

    @Override
public String getBodyContentType() {
return PROTOCOL_CONTENT_TYPE;
}

PS:设置Content-Type也能够通过复写getBodyContentType这个函数,而不用总是麻烦的使用getHeader中的map进行设定,两种设定方式效果一致。并且也不用操心编码格式。由于默认就是utf-8的:

    /** 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);

到这里,Json请求的相关使用方法也就介绍完了。下一节将会从源代码角度分析一下Volley请求的逻辑顺序到底是如何的,假设我们须要书写自己的请求类型,都须要复写哪些函数。以及须要注意些什么。

源代码

关于Volley和Cloudant很多其它的通信细节,见CloudantVolley项目:https://github.com/airk000/CloudantVolley

Android应用开发:网络工具——Volley(一)的更多相关文章

  1. Android应用开发:网络工具——Volley(二)

    引言 在Android应用开发:网络工具--Volley(一)中结合Cloudant服务介绍了Volley的一般使用方法.当中包括了两种请求类型StringRequest和JsonObjectRequ ...

  2. Android框架之网络开发框架Volley

    1. Volley简单介绍 我们平时在开发Android应用的时候不可避免地都须要用到网络技术.而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据.Android系统中主要提供了两种方式来进 ...

  3. Android应用开发-网络编程(一)(重制版)

    网络图片查看器 1. 确定图片的网址 2. 发送http请求 URL url = new URL(address); // 获取客户端和服务器的连接对象,此时还没有建立连接 HttpURLConnec ...

  4. Android应用开发-网络编程(一)

    网络图片查看器 1. 确定图片的网址 2. 发送http请求 URL url = new URL(address); // 获取客户端和服务器的连接对象,此时还没有建立连接 HttpURLConnec ...

  5. Android应用开发-网络编程(二)(重制版)

    Apache HttpClient框架 GET方式请求提交数据 1. 创建一个HttpClient HttpClient hc = new DefaultHttpClient(); 2. 创建一个Ht ...

  6. Android应用开发高效工具集1---ant构建简单Android项目

    本文转载于:http://blog.csdn.net/lincyang/article/details/40950153 在java编译那些事儿中提到了用ant去编译Java项目,今天扩展到用它来构建 ...

  7. Android SDK开发常用工具的使用及其异常处理

    由于以下操作都是命令操作,所以在执行以下操作之前确保环境变量 ANDROID_HOME 指向的是正确的Android SDK的路径: 一.启动Android SDK Manager: android ...

  8. Android应用开发-网络编程(二)

    Apache HttpClient框架 GET方式请求提交数据 1. 创建一个HttpClient HttpClient hc = new DefaultHttpClient(); 2. 创建一个Ht ...

  9. 配置Android应用开发环境

    详解JRE.JDK.SDK.ADT请点击辨析ADK&JVM&JRE&JDK&ADT 一.安装JDK 开发 Android应用程序的时候,仅有Java运行环境(Java ...

随机推荐

  1. 最长k可重区间集(cogs 743)

    «问题描述:«编程任务:对于给定的开区间集合I和正整数k,计算开区间集合I的最长k可重区间集的长度.«数据输入:由文件interv.in提供输入数据.文件的第1 行有2 个正整数n和k,分别表示开区间 ...

  2. 沼泽鳄鱼(bzoj 1898)

    Description 潘塔纳尔沼泽地号称世界上最大的一块湿地,它地位于巴西中部马托格罗索州的南部地区.每当雨季来临,这里碧波荡漾.生机盎然,引来不少游客.为了让游玩更有情趣,人们在池塘的中央建设了几 ...

  3. Android使用圆角

    圆角Button 效果图 绿色Button 定义button_green.xml资源文件位于drawable文件夹下,可用作button的background属性 button_green.xml: ...

  4. saltstack 模块学习之 state

     入口文件top.sls 三要素环境:通过file-roots指定目标主机:可以使用通配符*配置文件路径:路径分割符为. 比如a.mysql 表示在环境指定的路径下有个a目录,a目录下有个mysql. ...

  5. pyinstaller打包exe程序各种坑!!!

    pyinstaller打包python成exe可执行程序,各种报错,各种坑,在次记录下 一.pyinstaller打包报错for real_module_name, six_moduleAttribu ...

  6. DOM和jquery对象之间的转换

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. AC日记——换教室 洛谷 P1850

    题目描述 对于刚上大学的牛牛来说, 他面临的第一个问题是如何根据实际情况中情合适的课程. 在可以选择的课程中,有2n节课程安排在n个时间段上.在第 i ( 1≤ i≤n)个时同段上, 两节内容相同的课 ...

  8. 在Android 7.0以上PopupWindow.showAsDropDown()不起作用问题

    最近优化界面,调用PopupWindow.showAsDropDown()发现,窗口并没有在控件下方显示. 有网友说是7.0以上系统的问题,可以自定义PopupWindow,重写showAsDropD ...

  9. 通用mapper的框架

    这两个框架都是一个大神写的.用来做单表的增删改查,爽爽的. 但是复杂的查询还不知道如何用,所以我还按传统的方式 写 service maperr ,写SQL来处理复杂查询,与多表的查询.  它的复杂查 ...

  10. Codeforces 815 C Karen and Supermarket

    On the way home, Karen decided to stop by the supermarket to buy some groceries. She needs to buy a ...