您的位置:首页 > 理论基础 > 计算机网络

Android之利用volley搭建简洁网络框架

2017-04-09 17:38 417 查看

Android之利用volley搭建简洁网络框架

文章链接:

知识点:

为什么一定要联网操作;

利用volley搭建合适自己的简介网络请求框架;

新名词记录{枚举;手动解析json}

概述

在当今互联网大潮中,中国的网络已经很普及了,互联网已经不是一个新鲜的词语。我们也是搭上了互联网快车,而且是移动互联网这一节车厢。

如今,在进行APP开发中,使用网络请求数据已经是每个APP必备的内容了。我敢说是一定有的,因为你不需要为用户提供账号系统和存储等,至少都要“收集用户信息”,你的APP被每一位用户握在手里,这是最快捷触达用户的途径了。

“用户为中心”一直是我们公司的的口号之一。那么要了解用户,就需要获取用户的各种信息,才能够更加好的“运营用户”。

所以,这里是总结:每一个APP都需要进行联网。

如果没有联网操作的APP,那就是在耍流氓了。没有谁会丢这么一个APP到用户手里吧?!

完。。。。。。

打造联网框架

俗话说:我们要站在巨人的肩膀上。联网的巨人之一就是volley。如果大家对volley还不熟悉,可以去百度,里面大把的教程。我这里对其进行封装,打造自己的简单易用的网络框架。

我已经将代码注释的很清楚了。各位看官慢慢品尝。

第一步:实体基类 AbsBaseBean.java

package com.yaojt.sdk.java;

import com.yaojt.sdk.java.utils.CommonLog;

import org.json.JSONObject;

import java.io.Serializable;

/**
* desc:基类basebean
* <p>
* author:kuyu.yaojt (tanksu)
* <p>
* email:yaojt@kuyumall.com
* <p>
* blog:http://blog.csdn.net/qq_16628781
* <p>
* date:17/4/9
*/

public abstract class AbsBaseBean implements Serializable {
private String TAG = AbsBaseBean.class.getSimpleName();
/**
* 请求成功码
*/
public final String SUCCESS_CODE = "0";
/**
* 系统错误,返回码
*/
public final String SYSTEM_ERROR_CODE = "-1";
/**
* 密码错误返回码
*/
public final String INVALID_PARAMS_CODE = "1";

/**
* token不可用返回码
*/
private final String EMPTY_TOKEN_CODE = "-3";
/**
* 需要重新登录的返回码
*/
private final String LOGOUT_CODE = "-4";

private String code;
private String message;
private String sign;

private String decodeData;
private String originalData;

ResponseStatus mResponseStatus;

/**
* 解析返回的数据
*
* @param response 返回的数据
*/
public void parseResponse(String response) {
if (response == null || response.equals("")) {
mResponseStatus = ResponseStatus.RESPONSE_EXCEPTION;
return;
}
try {

JSONObject jsonObject = new JSONObject(response);
code = jsonObject.optString("code");
message = jsonObject.optString("message");
mResponseStatus = SUCCESS_CODE.equals(code) ?
ResponseStatus.SUCCESS :
(SYSTEM_ERROR_CODE.equals(code) ?
ResponseStatus.SERVICE_EXCEPTION : ResponseStatus.PARAMS_EXCEPTION);
//检查是否被挤下线
if (LOGOUT_CODE.equals(code) || EMPTY_TOKEN_CODE.equals(code)) {
mResponseStatus = ResponseStatus.LOGOUT;
//下线处理后续操作
}
originalData = jsonObject.optString("data");
if (null == originalData || "null".equals(originalData) || "".equals(originalData)) {
mResponseStatus = ResponseStatus.PARAMS_EXCEPTION;
//toast提示
return;
}
//如果有传输加密,对数据进行解密
//decodeData = EncryptUtil.doubleDecrypt(originalData);
decodeData = originalData;
CommonLog.logInfo("decodeData", decodeData);
if ("[]".equals(decodeData) || "{}".equals(decodeData)) {
mResponseStatus = ResponseStatus.PARAMS_EXCEPTION;
//ToastUtils.makeText(MyApplication.getInstance(), message, ToastUtils.ONE_SECOND);
return;
}
//手动解析数据
parseData(originalData, decodeData);
} catch (Exception e) {
mResponseStatus = ResponseStatus.OTHER_ERROR;
e.printStackTrace();
}
}

/**
* data数据体
*
* @param orign  原始数据
* @param decode 解密数据
*/
public abstract void parseData(String orign, String decode);

/**
* 从JSON中取key对应的值,无值是返回默认值
*
* @param object       JSONObject
* @param key          值对应的key
* @param defaultValue 默认值
* @return value 如果有对应的key,则返回对应的值,反之返回defaultValue
*/
protected String getStringFromJsonObject(JSONObject object, String key, String defaultValue) {
if (null == object || null == key) return defaultValue;
return object.has(key) ? object.optString(key) : defaultValue;
}

/**
* 返回结果状态
*/
public enum ResponseStatus {
/**
* 成功
*/
SUCCESS,
/**
* 返回数据异常
*/
RESPONSE_EXCEPTION,
/**
* 网络连接失败
*/
NETWORK_ERROR,
/**
* 服务异常
*/
SERVICE_EXCEPTION,
/**
* 参数异常
*/
PARAMS_EXCEPTION,
/**
* 其他 错误
*/
OTHER_ERROR,
/**
* 登录过期
*/
LOGOUT
}

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public String getSign() {
return sign;
}

public void setSign(String sign) {
this.sign = sign;
}

public String getDecodeData() {
return decodeData;
}

public void setDecodeData(String decodeData) {
this.decodeData = decodeData;
}

public String getOriginalData() {
return originalData;
}

public void setOriginalData(String originalData) {
this.originalData = originalData;
}

public ResponseStatus getmResponseStatus() {
return mResponseStatus;
}

public void setmResponseStatus(ResponseStatus mResponseStatus) {
this.mResponseStatus = mResponseStatus;
}
}


上面的代码主要有几点:

1. 你需要一个volley.jar的包;

2. 定义一系列的请求返回码(需要和后台商定);

3. 定义一个请求异常枚举(ResponseStatus);

4. parseResponse(String response)方法对原始的数据进行处理:如果没有加密,直接从json中获取到数据;如果有加密,需要进行解密之后才进行操作;最后调用parseData()方法进行手动解析数据,所以要求所有的实体类都要继承此基本实体类;此类只是对共有的几个属性值和结果进行判断,将具体的操作给到子类进行处理;

5. 一些基本的setter,getter方法;

第二步:进行网络封装

在这里,实现默认已经加入volley的代码。

因为我们就是使用volley进行网络请求处理的。

我们这里主要是利用volley进行< JSONObject>请求,因为绝大多数的网络传输都是使用json。我们这里也不例外,不过项目里面对数据进行了aes+des双重加密。

具体代码如下所示:JsonRequestImpl.java

package com.yaojt.sdk.java.network;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import com.yaojt.sdk.java.utils.CommonLog;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
* desc:自定义请求,利用map传參
* <p>
* author:kuyu.yaojt (tanksu)
* <p>
* email:yaojt@kuyumall.com
* <p>
* blog:http://blog.csdn.net/qq_16628781
* <p>
* date:17/4/9
*/

public class JsonRequestImpl extends Request<JSONObject> {
private Map<String, String> mMap;
private Response.Listener<JSONObject> mListener;
//private AppSharedPreferences appSharedPreferences;

/**
* 构造方法
*
* @param url           请求地址
* @param listener      成功监听器
* @param errorListener 错误监听器
* @param map           入参数据
*/
public JsonRequestImpl(int method, String url, Response.Listener<JSONObject> listener,
Response.ErrorListener errorListener, Map<String, String> map) {
super(Request.Method.POST, url, errorListener);
mListener = listener;
mMap = map;
this.method = method;
}

private int method;

@Override
public Map<String, String> getHeaders() throws AuthFailureError {
return addHeaders(method == 1 ? "POST" : (method == 2 ? "PUT" : "GET") + "-Header");
}

/**
* <li>请求header</li>
*
* @param tag 日志标记请求类型
* @return headers
*/
protected Map<String, String> addHeaders(String tag) {
Map<String, String> header = new HashMap<>();
//String accessToken = new AppSharedPreferences(MyApplication.getInstance()).getAccessToken();
String accessToken = "123456789";
String str = null;
try {
String byteStr = new String(accessToken.getBytes(), "utf-8");
str = URLEncoder.encode(byteStr, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
header.put("login-token", str); //带入token
CommonLog.logInfo(tag, header.toString());
return header;
}

@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse networkResponse) {
try {
String jsonStr = new String(networkResponse.data, HttpHeaderParser.parseCharset(networkResponse.headers));
return Response.success(new JSONObject(jsonStr), HttpHeaderParser.parseCacheHeaders(networkResponse));
} catch (UnsupportedEncodingException | JSONException e) {
e.printStackTrace();
}
return null;
}

@Override
protected void deliverResponse(JSONObject jsonObject) {
if (null != mListener) mListener.onResponse(jsonObject);
}

//mMap是已经按照前面的方式,设置了参数的实例
@Override
protected Map<String, String> getParams() throws AuthFailureError {
return mMap;
}

}


说明:

1. 传入必要的参数URL,入参,成功监听和失败监听;

2. 请求的头部加入信息,例如token等等;

第三步:便捷使用

下面这个使用类就比较简单了。

package com.yaojt.sdk.java.network;

import android.content.Context;

import com.android.volley.toolbox.Volley;
import com.yaojt.sdk.java.AbsBaseBean;
import com.yaojt.sdk.java.i.RequestCallBack;

import java.util.Map;

/**
* desc:sdk中的网络请求处理类
* 注意:这里有一个问题,当用户传入的是activity的context,会造成内存泄漏
* 所以建议将此类卸载可以引用application的module下面
* <p>
* author:kuyu.yaojt (tanksu)
* <p>
* email:yaojt@kuyumall.com
* <p>
* blog:http://blog.csdn.net/qq_16628781
* <p>
* date:17/4/9
*/

public class HttpRequestHandler extends AbsHttpRequest {

protected static final String DEVICE = "Android";
protected static final String VERSION = "1.0";

private static HttpRequestHandler sVolleyHandler;

/**
* 构造函数私有化
*/
private HttpRequestHandler(Context context) {
super();
mRequestQueue = Volley.newRequestQueue(context);
}

/**
* 网络请求单例模式
*
* @return VolleyHandler
*/
public static HttpRequestHandler getInstance(Context context) {
if (sVolleyHandler == null) {
synchronized (HttpRequestHandler.class) {
if (sVolleyHandler == null) {
sVolleyHandler = new HttpRequestHandler(context);
}
}
}
return sVolleyHandler;
}

/**
* post json请求
*
* @param url       请求链接地址
* @param params    post请求参数
* @param baseModel BaseModel
* @param callBack  TaskCallBack
*/
public void postJsonRequest(Context context, String url, final Map<String, String> params,
final AbsBaseBean baseModel, final RequestCallBack callBack) {
super.postJsonRequest(context, url, params, baseModel, callBack);
}

@Override
protected boolean checkNetworkVisiable() {
//网络检查操作
return true;
}

}


说明:

1. 使用单例并加锁的方式保证单例唯一性和安全性;

2. 提供一个post方式的网络请求方法给外部调用;

3. 网络检查部分代码没有实现,需要自己去实现;

注意:这里有一个问题,当用户传入的是activity的context,会造成内存泄漏所以建议将此类卸载可以引用application的module下面。我这里使用的是sdk的一个module,不能够直接应用application的实现类。

总结

上面的使用方式很简介,对于网络请求的底层,例如线程、线程池等等,volley都做了比较好的封装,我们只管上层的调用开发,不用关注细节。

当然,也有不好的,我们毕竟还是需要知道线程的创建和使用等等的知识。这一块是进阶的必备功课。接下来我也会新开一篇文章,讲解利用最原始的方式进行网络请求框架的搭建和使用。

以上就是所有内容,如有任何问题,请及时与我联系,谢谢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息