网上有很多封装的很好用的网络请求框架如国内开源的Afinal,Xutils,JKFramework,都是良心之作,github上都有源码,还有网络上比较流行的AsyncHttpClient,OkHttp,Volley,Retrofit,Ion等等,我选择了Volley作为我项目的请求框架,原因有如下:
1、Volley是Google官方提供的,它的设计就是为Android网络交互而生的,非常适合数据量小而网络操作频繁的请求操作
2、Volley具有极强的可扩展性,底层数据传输可用Okhttp代替,Okhttp的传输速度更快
为了更利于项目的扩展和维护,我并没有直接拿来用,而是先进行了一层封装操作,Volley有一个很明显的优势,就是采用了队列的形式请求,一个简单的请求
RequestQueue queue = Volley.newRequestQueue(this);
StringRequest stringRequest = new StringRequest(Request.Method.GET, "url", new Response.Listener() {
@Override
public void onResponse(String response) {
System.out.println("response = " + response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
queue.add(stringRequest);
创建一个请求队列,新建一个请求,将请求丢入请求队列,其他的事情就不用管了,等返回response结果就行了,很简单。
但实际项目中我不会每次请求都会创建一个RequestQueue,这样很浪费资源,也不符合Volley的设计理念,相当于我们要创建无数个队列(如果这样做还不如不用Volley),我们要保持Application的生命周期中只存在一个队列,我会创建一个请求的管理类来管理所有的请求,设计大概是这样的
public class HttpClient {
public static RequestQueue queue = Volley.newRequestQueue(App.getContext());
public static void postRequest(String url) {
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener() {
@Override
public void onResponse(String response) {
System.out.println("response = " + response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
queue.add(request);
}
}
所有的请求都用HttpClient调用requestPost方法就可以保持整个App的生命周期就只有一个请求队列了,虽然解决了第一步,还是有很多要做的,我要得到response的数据或者错误信息,要怎么做呢?使用接口回调,下面看一下,简单的接口实现
public interface OnResponseListener {
void success(String response);
void failure(String errorMessage);
}
HttpClient代码改为
public class HttpClient {
public static RequestQueue queue = Volley.newRequestQueue(App.getContext());
public static void postRequest(String url, final OnResponseListener listener) {
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener() {
@Override
public void onResponse(String response) {
listener.success(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
listener.failure(error.getLocalizedMessage());
}
});
queue.add(request);
}
}
使用
HttpClient.postRequest("http://www.baidu.com", new OnResponseListener() {
@Override
public void success(String response) {
System.out.println("response = " + response);
}
@Override
public void failure(String errorMessage) {
System.out.println("errorMessage = " + errorMessage);
}
});
只是改头换面,没有太大的改变,继续往下分析,我们还有那些事要处理,数据得到了,网络的交互用的大都是用json数据,我们需要对json数据进行解析,一般都是用对象去接收,要开始下一版的代码了
public class HttpClient {
public static RequestQueue queue = Volley.newRequestQueue(App.getContext());
public static final String RESULT_CODE = "code"; //状态码,后台返回成功或者失败
public static final String RETURN_MESSAGE = "message";//消息,后台返回的文本消息,提示或者错误信息
public static final String RESULT = "result";//成功的返回结果
public static final String SUCCESS = "1"; //成功
public static final String FAILURE = "0";//失败
public static void postRequest(String url, final OnResponseListener listener) {
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener() {
@Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);//将json数据转化为json对象
if (!jsonObject.isNull(RESULT_CODE)) {//判断code字段是否存在
String code = jsonObject.getString(RESULT_CODE);//活得code的值
if (code.equals(SUCCESS)){ //成功则继续往下判断
if (!jsonObject.isNull(RESULT)){
String result = jsonObject.getString(RESULT);
listener.success(result);
}
}else if (code.equals(FAILURE)){//失败返回错误信息
if (!jsonObject.isNull(RETURN_MESSAGE)) {//判断message字段是否存在
listener.failure(jsonObject.getString(RETURN_MESSAGE));//返回后台失败信息
}
}else {
listener.failure("无效的状态码");//返回状态码无效的错误信息
}
}else {
listener.failure("状态码不存在");//返回状态码不存在的错误信息
}
} catch (JSONException e) {
e.printStackTrace();
listener.failure(e.getLocalizedMessage());//返回json异常的错误信息
}
listener.success(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
listener.failure(error.getLocalizedMessage());//返回Volley异常的错误信息
}
});
queue.add(request);//将请求添加到队列
}
}
到这里,已经将返回的结果进行了处理,而且做了一个错误收集的工作,在failure可以直观的看到任何错误信息,对我们接口调试,应该是很有帮助的,当然你可能会问上面那些字段怎么来的,这些工作需要与后台协商约定,你也可以不叫这些名字,这些都无所谓,下面继续走,看看这段程序还缺什么,既然是请求,当然还需要有请求参数,还有返回的result还是json数据,使用的时候还需要进行手动解析,如下:
public class HttpClient {
public static RequestQueue queue = Volley.newRequestQueue(App.getContext());
public static final String RESULT_CODE = "code"; //状态码,后台返回成功或者失败
public static final String RETURN_MESSAGE = "message";//消息,后台返回的文本消息,提示或者错误信息
public static final String RESULT = "result";//成功的返回结果
public static final String SUCCESS = "1"; //成功
public static final String FAILURE = "0";//失败
public static void postRequest(String url, final Map map, final OnResponseListener listener) {
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener() {
@Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);//将json数据转化为json对象
if (!jsonObject.isNull(RESULT_CODE)) {//判断code字段是否存在
String code = jsonObject.getString(RESULT_CODE);//活得code的值
if (code.equals(SUCCESS)){ //成功则继续往下判断
if (!jsonObject.isNull(RESULT)){
String result = jsonObject.getString(RESULT);
listener.success(result);
}
}else if (code.equals(FAILURE)){//失败返回错误信息
if (!jsonObject.isNull(RETURN_MESSAGE)) {//判断message字段是否存在
listener.failure(jsonObject.getString(RETURN_MESSAGE));//返回后台失败信息
}
}else {
listener.failure("无效的状态码");//返回状态码无效的错误信息
}
}else {
listener.failure("状态码不存在");//返回状态码不存在的错误信息
}
} catch (JSONException e) {
e.printStackTrace();
listener.failure(e.getLocalizedMessage());//返回json异常的错误信息
}
listener.success(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
listener.failure(error.getLocalizedMessage());//返回Volley异常的错误信息
}
}){
@Override
protected Map getParams() throws AuthFailureError {
return map;
}
};
queue.add(request);//将请求添加到队列
}
使用
Map<String,String> map = new HashMap<>();
map.put("key1","value1");
map.put("key2","value1");
...
HttpClient.postRequest("http://www.baidu.com",map, new OnResponseListener() {
@Override
public void success(String result) {
System.out.println("result = " + result);
//这里我新建了一个测试的对象,采用了gson来将json数据转换为bean对象
//解析成对象,嵌套的对象也是可以的
TestBean testBean = new Gson().fromJson(result, TestBean.class);
//解析成list
Type type = new TypeToken<ArrayList<TestBean>>() {
}.getType();
List<TestBean> testBeans = new Gson().fromJson(result, type);
//解析成数组
TestBean[] testBeans1 = new Gson().fromJson(result, TestBean[].class);
//这个时候想转化为list可以调用下面的方法
List testBeans2 = Arrays.asList(testBeans1);
}
@Override
public void failure(String errorMessage) {
System.out.println("errorMessage = " + errorMessage);
}
});
到这里,我们已经可以得到数据,其他的工作就和他没什么关系了,再来检查一下我们还可以做那些事,一般在请求之前都需要检查网络状态的,可以这样做
//判断网络是否连接
if (NetworkUtils.isConnectedByState(App.getContext())) {
queue.add(request);//将请求添加到队列
}else {
listener.failure("网络未连接");//返回网络未连接的错误信息
}
基本的框架算是出来了,不过还有一些细节的优化,下一篇继续讲解