Android使用Volley之JsonObjectRequest访问网络
Volley是一个为Android开发提供更快捷更健壮更简单的网络操作框架。
Volley非常适合去进行数据量不大、但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕,就不适合了。
引入
有两种方式:
1、下载jar包导入项目(适合离线开发)
切换到“Project”视图,找到app/libs目录,将volley.jar复制到libs文件夹下,右键选择【Add As Library】
2、在build.gradle中引入依赖(推荐这种方式)
implementation 'com.android.volley:volley:1.2.1'
步骤
1、创建一个请求队列RequestQueue
2、创建Request对象
3、将请求对象添加到请求队列中
实现
1、AndroidManifest.xml中添加网络访问权限
<uses-permission android:name="android.permission.INTERNET" />
2、禁用掉明文流量请求的检查
参见 https://www.cnblogs.com/lihuawei/p/16458853.html 中的“禁用掉明文流量请求的检查”部分。
3、创建请求队列
与一般的网络请求不同,Volley把所有请求都保存在一个请求队列中,然后在请求队列中按优先级一个一个取出请求,然后发送出去,因此我们先要实例化一个请求队列。
private static RequestQueue requestQueue; requestQueue = Volley.newRequestQueue(getApplicationContext()); //把上下文context作为参数传递进去
4、创建请求对象
三种请求
在Volley内,一般的Http请求对象有三种,分别是StringRequest,JsonObjectRequest和JsonArrayRequest。
而每个对象都可以使用GET和POST请求方式。
从它们的名字可以知道,
StringRequest是请求一段字符串,
JsonObjectRequest是请求一个JSON对象,
JsonArrayRequest是请求一组JSON数组。
我们从最简单的StrringRequest说起。
(1)StringRequest
我们先来了解一下他的构造方法,第2个构造方法就是默认GET(method=0)请求方式
/** * @param method 请求的方式,可以选择GET或者POST * url 请求的网址 * listener 请求成功的回调函数 * errorListener 请求失败的回调函数 */ public StringRequest(int method, String url, com.android.volley.Response.Listener<String> listener, com.android.volley.Response.ErrorListener errorListener) { super(method, url, errorListener); this.mLock = new Object(); this.mListener = listener; } public StringRequest(String url, com.android.volley.Response.Listener<String> listener, com.android.volley.Response.ErrorListener errorListener) { this(0, url, listener, errorListener); }
通过构造方法获取StringRequest的实例后,通过把这个实例添加进请求队列中,就能正常地进行网络通信了。
下面我们来实战一下,以大赛提供的平台获取新闻列表为例(http://218.7.112.123:10001/prod-api/press/press/list)
public void submitString() { RequestQueue queue = Volley.newRequestQueue(getApplicationContext()); // 或传参MainActivity.this StringRequest request = new StringRequest("http://218.7.112.123:10001/prod-api/press/press/list", new com.android.volley.Response.Listener<String>() { @Override public void onResponse(String s) { Log.d(TAG, "onResponse: s = " + s); } }, new com.android.volley.Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Log.d(TAG, "onErrorResponse: volleyError = " + volleyError.getMessage()); } }); queue.add(request); }
运行之后,即可以得到服务器返回的字符串类型的结果,保存在onResponse(String s)方法的参数s中。
如果我们发现s中的中文字符是乱码,是因为Volley里面默认编码为ISO-8859-1 (Latin1),不是utf-8,这时我们需要重写StringRequest的parseNetworkResponse()这个方法。
public void submitString() { RequestQueue queue = Volley.newRequestQueue(getApplicationContext()); StringRequest request = new StringRequest("http://218.7.112.123:10001/prod-api/press/press/list", new com.android.volley.Response.Listener<String>() { @Override public void onResponse(String s) { Log.d(TAG, "onResponse: s = " + s); } }, new com.android.volley.Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Log.d(TAG, "onErrorResponse: volleyError = " + volleyError.getMessage()); } }) { @Override protected com.android.volley.Response<String> parseNetworkResponse(NetworkResponse response) { String parsed = null; try { parsed = new String(response.data, "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return com.android.volley.Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); } }; queue.add(request); }
(2)JsonObjectRequest和JsonArrayRequest
以上两个类的用法和StringRequest很类似,同样有着GET和POST的请求方式。
JsonObjectRequest 和 JsonArrayRequest有着一个共同的父类JsonRequest。
JsonObjectRequest请求的是一个JSON对象,而JsonArrayRequest请求的是一个JSON数组,这里就以JsonObjectRequest为代表讲述。
我们先看看构造器:
public JsonObjectRequest(int method, String url, JSONObject jsonRequest, com.android.volley.Response.Listener<JSONObject> listener, com.android.volley.Response.ErrorListener errorListener) { super(method, url, jsonRequest == null ? null : jsonRequest.toString(), listener, errorListener); } public JsonObjectRequest(String url, JSONObject jsonRequest, com.android.volley.Response.Listener<JSONObject> listener, com.android.volley.Response.ErrorListener errorListener) { this(jsonRequest == null ? 0 : 1, url, jsonRequest, listener, errorListener); }
从构造器可以看出,它和StringRequest的构造方法大同小异,但有一点要注意的是,JsonObjectRequest和JsonArrayRequest的构造参数有一个是JSONObject jsonRequest,这个就是Json形式的请求体。
如果是POST请求,我们就要提前使用JSONObject的构造方法和put方法,创建一个对象,然后通过JsonObjectRequest构造器把请求体传进去,而不用像StringRequest那样通过重写父类的getParams()来写入请求参数。
实例化了请求实例后,添加进请求队列即可。
我们以大赛平台用户登录为例。
public void submitJsonObject() { try { JSONObject jsonObject = new JSONObject(); jsonObject.put("username", "panda"); jsonObject.put("password", "123456"); RequestQueue queue = Volley.newRequestQueue(getApplicationContext()); // MainActivity.this JsonObjectRequest request = new JsonObjectRequest(com.android.volley.Request.Method.POST, "http://218.7.112.123:10001/prod-api/api/login", jsonObject, new com.android.volley.Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject jsonObject) { Log.d(TAG, "onResponse: jsonObject = " + jsonObject); LoginData loginData = new Gson().fromJson(jsonObject.toString(), LoginData.class); Log.d(TAG, "onResponse: loginData = " + loginData.getMsg()); Log.d(TAG, "onResponse: loginData = " + loginData.getCode()); Log.d(TAG, "onResponse: loginData = " + loginData.getToken()); } }, new com.android.volley.Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Log.d(TAG, "onResponse: volleyError = " + volleyError.getMessage()); } }); queue.add(request); } catch (JSONException e) { e.printStackTrace(); } }
其中存放登录数据的LoginData.java类的源码如下:
public class LoginData { private int code; private String msg; private String token; public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } @Override public String toString() { return "LoginData{" + "code=" + code + ", msg='" + msg + '\'' + ", token='" + token + '\'' + '}'; } }
我们上面的例子就是使用了POST的请求方式。
如果我们需要在请求的时候,设置请求头(Header)的话,我们可以重写getHeaders()方法。
例如,有的请求需要安全认证的接口,需要在请求头设置认证信息, 格式如下:
参数: Authorization
参数值: 登录获取 TOKEN
有的请求需要设置参数Content-Type,参数值application/json; charset=utf-8,我们都可以在重写的getHeaders()方法使用Map来设置。
我们以大赛平台查询个人基本信息为例。
public void submitJsonObject() { RequestQueue queue = Volley.newRequestQueue(getApplicationContext()); // MainActivity.this JsonObjectRequest request = new JsonObjectRequest("http://218.7.112.123:10001/prod-api/api/common/user/getInfo", null, new com.android.volley.Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject jsonObject) { Log.d(TAG, "onResponse: jsonObject = " + jsonObject.toString()); } }, new com.android.volley.Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Log.d(TAG, "onResponse: volleyError = " + volleyError.getMessage()); } }) { @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); map.put("Authorization", Constant.TOKEN); map.put("Content-Type", "application/json; charset=utf-8"); return map; } }; queue.add(request); }
如果是GET请求,需要提设置请求参数,我们就需要重写
我们以大赛平台查询电子钱包变动记录为例。
public void balanceList() { RequestQueue queue = Volley.newRequestQueue(getApplicationContext()); JsonObjectRequest request = new JsonObjectRequest( "http://218.7.112.123:10001/prod-api/api/common/balance/list", null, new com.android.volley.Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject jsonObject) { Log.d(TAG, "onResponse: jsonObject = " + jsonObject); } }, new com.android.volley.Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Log.d(TAG, "onResponse: volleyError = " + volleyError.getMessage()); } }) { @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); map.put("Authorization", Constant.TOKEN); map.put("Content-Type", "application/x-www-form-urlencoded"); return map; } @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); map.put("pageNum", "1"); map.put("pageSize", "8"); return map; } }; queue.add(request); }