笔者将通过11篇博客对个人开源框架进行讲解,本篇为第3篇,讲解代码实现,公共部分。
如果有兴趣一起讨论本框架的内容,请加QQ群:271335749
回顾一下上一篇的内容,从一个入口,到实现内部细节,从公共模块到后面的分支模块,到最后可以使用框架。
一起再来看看经过上一篇对框架的构造,该怎样使用框架。
假设服务端返回的数据是这样的:
{
"code":"00001",
"message":"login success",
"time":"1479807260",
"data":{
"id":"123",
"name":"chenjian"
}
}
data里面放着是用户数据,你需要定义一个Bean,他继承NetBaseBean
public class NetUserBean extends NetBaseBean {
private String id;
private String name;
@Override
public void initByJson(JSONObject jsonObject) throws JSONException {
this.id = jsonObject.optString("id");
this.name = jsonObject.optString("name");
}
}
initByJson方法中,我们用的是api里面的类来解析,而没用gson和fastjson等框架,当然你也可以使用。
再来看看使用
NetHelper.get("url", new NetSingleBeanListener<NetUserBean>() {
@Override
protected void onError(CallbackCode errorCode, NetRetBean netRetBean) {
// 这里是ui线程
}
@Override
protected void onSuccess(NetUserBean userBean) {
// 这里是ui线程
}
});
在本篇,我们将要实现公共部分的代码,即不包括内层解析监听器部分的代码。
和上一篇的思路一样,我们从入口开始,先是NetHelper类
package com.chenjian.net.helper;
import com.chenjian.net.core.async.NetExcutor;
import com.chenjian.net.core.async.NetListener;
import com.chenjian.net.data.NetConstants;
/**
* 网络请求工具类
* <p>
* 作者: ChenJian
* 时间: 2016.12.14 11:24
*/
public class NetHelper {
/**
* get异步请求
*
* @param url url
* @param listener 监听器
*/
public static void get(String url, NetListener listener) {
get(url, NetConstants.defaultWaitForToken, listener);
}
/**
* get异步请求
*
* @param url url
* @param isWaitForToken 是否等待token请求成功
* @param listener 监听器
*/
public static void get(String url, boolean isWaitForToken, NetListener listener) {
NetExcutor netExcutor = new NetExcutor();
netExcutor.setUrl(url);
netExcutor.setWaitForToken(isWaitForToken);
netExcutor.setExcutorListener(listener);
netExcutor.get();
}
/**
* post异步请求
*
* @param url url
* @param params 参数
* @param listener 监听器
*/
public static void post(String url, String params, NetListener listener) {
post(url, params, NetConstants.defaultWaitForToken, listener);
}
/**
* post异步请求
*
* @param url url
* @param params 参数
* @param isWaitForToken 是否等待token请求成功
* @param listener 监听器
*/
public static void post(String url, String params, boolean isWaitForToken, NetListener listener) {
NetExcutor netExcutor = new NetExcutor();
netExcutor.setUrl(url);
netExcutor.setParams(params);
netExcutor.setWaitForToken(isWaitForToken);
netExcutor.setExcutorListener(listener);
netExcutor.post();
}
}
这里多了一个参数,isWaitForToken。因为一些项目是需要用户登录的,其后的多数服务端请求,需要在用户登录成功之后,才能发起。通常的,我们在登录成功后,服务端会返回用户信息,或者一个字符串,总之是一个标识了你登录成功了的东西。如果服务端没有给你标识,你本地也会有一个标识。我们暂且把这个标识叫做token。接着往下看代码,也许很快就明白了。
NetConstants类非常简单,只是用来存放全局常量。目前只有一个常量
package com.chenjian.net.data;
/**
* 全局常量
* <p>
* 作者: ChenJian
* 时间: 2017.1.6 13:42
*/
public class NetConstants {
public static final boolean defaultWaitForToken = false;
}
package com.chenjian.net.core.async;
import android.os.AsyncTask;
import com.chenjian.net.core.common.RequestType;
import com.chenjian.net.request.RequestUtil;
import com.chenjian.net.token.TokenUtil;
/**
* 网络请求处理核心类
* <p>
* 作者: ChenJian
* 时间: 2016.12.13 17:42
*/
public class NetExcutor {
/**
* 请求url
*/
private String mUrl;
/**
* 请求类型
*/
private RequestType mRequestType;
/**
* post请求时的参数
*/
private String mParams;
/**
* 是否先等待token请求成功
*/
private boolean isWaitForToken;
/**
* 请求后的回调
*/
private NetListener mExcutorListener;
public void setUrl(String url) {
this.mUrl = url;
}
private void setRequestType(RequestType requestType) {
this.mRequestType = requestType;
}
public void setParams(String params) {
this.mParams = params;
}
public void setExcutorListener(NetListener listener) {
this.mExcutorListener = listener;
}
public void setWaitForToken(boolean waitForToken) {
isWaitForToken = waitForToken;
}
public void get() {
setRequestType(RequestType.REQUEST_TYPE_GET);
new NetTask().execute();
}
public void post() {
setRequestType(RequestType.REQUEST_TYPE_POST);
new NetTask().execute();
}
/**
* 网络请求异步任务,android 8 以上系统会自己对异步任务做线程池处理
* <p>
* 此处也可以改成自己去写线程池,让调用者可以配置线程池的相关参数
*/
private class NetTask extends AsyncTask<String, Integer, Boolean> {
@Override
protected Boolean doInBackground(String... params) {
if (isWaitForToken) {
TokenUtil.waitToken();
}
try {
String result = request();
mExcutorListener.sendSuccess(result);
return true;
} catch (Exception e) {
e.printStackTrace();
mExcutorListener.sendError(e);
return false;
}
}
}
private String request() throws Exception {
String result = null;
switch (mRequestType) {
case REQUEST_TYPE_GET:
result = RequestUtil.getRequest(mUrl);
break;
case REQUEST_TYPE_POST:
result = RequestUtil.postRequest(mUrl, mParams);
break;
default:
break;
}
return result;
}
}
package com.chenjian.net.core.common;
/**
* 网络请求类型
* <p>
* 作者: ChenJian
* 时间: 2016.12.14 13:34
*/
public enum RequestType {
REQUEST_TYPE_GET,
REQUEST_TYPE_POST,
}
这里增加了isWaitForToken,这个变量在NetTask的doInBackground里面使用到,在发起请求前,判断下,如果要等待token,那么就调用TokenUtil.waitToken(),为什么要这样呢?正如刚才所说,有些时候后面的请求需要依赖前面的登录,有可能每次请求都要带上登录成功返回的token为参数,不然服务端会认为你未登录,不会返回需要的数据给你。就像qq,通过qq号获取好友列表,必须在登录之后才行,不然信息也就太容易泄漏了。当然他们的做法可能非常复杂,这里只是简单的拿qq举例。
再看看TokenUtil里面做了什么
package com.chenjian.net.token;
import com.chenjian.net.data.NetVariables;
/**
* Created by ChenJian
* 2016.11.29 17:26:26.
*/
public class TokenUtil {
private static boolean isWaitToken = true;
public static void setWaitToken(boolean isWaitToken) {
TokenUtil.isWaitToken = isWaitToken;
}
/**
* 此方法只能在非ui线程中调用,慎用
*/
public static void waitToken() {
while (isWaitToken) {
if (NetVariables.token != null && !NetVariables.token.equals("")) {
break;
}
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
NetVariables里面放首全局变量。目前也就一个变量
package com.chenjian.net.data;
/**
* 全局变量
* <p>
* Created by ChenJian
* 2016.11.24 9:56:56.
*/
public class NetVariables {
public static String token;
}
waitToken方法里,很无脑的,隔一秒就检测一次token,如果检测不通过,就继续等待。这样的话,前面的NetTask在token检测不通过的时候,就会一直等待,直接检测通过后,才会开始请求。当然,等待的前提是isWaitForToken为true。
如果你的App不需要用到这个功能,就直接把NetVariables里面的defaultWaitForToken初始值设置为false。
如果需要,就设为true。设为true时,如果部分请求不需要等待token,NetHelper提供了重载的几个方法,通过传参数,设置不等待token。
这里的做法只是笔者个人想法的实现,如果大家觉得做得不好,有更好的办法的话,可以自行修改代码,或者加博文开头写的qq群一起讨论。
继续深入到网络请求工具类里面RequestUtil
package com.chenjian.net.request;
import android.util.Log;
import com.chenjian.net.aes.AesUtil;
import com.chenjian.net.demo.util.LogUtil;
/**
* 对Http请求进行包装,涉及到加解密以及其它内容等,都放到这个类里面处理,而不与HttpUtil耦合
* <p>
* 作者: ChenJian
* 时间: 2016.12.14 14:32
*/
public class RequestUtil {
private static String TAG = RequestUtil.class.getName();
/**
* get请求
*
* @param url url
* @return 返回请求的结果
* @throws Exception
*/
public static String getRequest(String url) throws Exception {
String ret;
Log.d(TAG, "request: " + url);
String tmp = HttpUtil.get(url);
Log.d(TAG, "response: " + " ret: " + tmp);
ret = AesUtil.decryptToString(tmp);
Log.d(TAG, "response: " + " ret: " + ret);
return ret;
}
/**
* post请求
*
* @param url url
* @param param post请求的参数
* @return 返回请求的结果
* @throws Exception
*/
public static String postRequest(String url, String param) throws Exception {
String ret;
LogUtil.d(TAG, "request: " + url + " param: " + param);
String data = AesUtil.encryptToString(param);
String tmp = HttpUtil.post(url, data);
LogUtil.d(TAG, "response: " + " ret: " + tmp);
ret = AesUtil.decryptToString(tmp);
LogUtil.d(TAG, "response: " + " ret: " + ret);
return ret;
}
}
只是进行简单的加密,请求,解密。如果请求前和请求后有其它业务需求,可以在这里添加,而不和HttpUtil耦合。
来看看加密工具类AesUtil
package com.chenjian.net.aes;
/**
* AES加解密包装工具类
* <p>
* 作者: ChenJian
* 时间: 2016.12.14 15:36
*/
public class AesUtil {
public static String encryptToString(String encryptStr) {
if (encryptStr == null) {
return "";
}
return encryptStr;
}
public static String decryptToString(String decryptStr) {
if (decryptStr == null) {
return "";
}
return decryptStr;
}
}
再看看HttpUtil类,这个类大家应该比较熟悉了
package com.chenjian.net.request;
import com.chenjian.net.exp.RequestErrorException;
import com.chenjian.net.exp.RespondErrorException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* Http请求工具类
* <p>
* 作者: ChenJian
* 时间: 2016.12.14 13:53
*/
public class HttpUtil {
private static final int CONNECT_TIMEOUT = 1000 * 10;
private static final int READ_TIMEOUT = 1000 * 10;
private static final int BUF_SIZE = 1024 * 10;
public static String post(String requestUrl, String param) throws Exception {
HttpURLConnection conn = null;
OutputStream out = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
URL url = new URL(requestUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setConnectTimeout(CONNECT_TIMEOUT);
conn.setReadTimeout(READ_TIMEOUT);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.connect();
out = conn.getOutputStream();
if (param != null && param.length() > 0) {
out.write(param.getBytes());
}
int code = conn.getResponseCode();
if (code != HttpURLConnection.HTTP_OK) {
throw new RespondErrorException(code);
}
is = conn.getInputStream();
byte[] tmp = new byte[BUF_SIZE];
baos = new ByteArrayOutputStream();
int len = is.read(tmp);
while (len != -1) {
baos.write(tmp, 0, len);
len = is.read(tmp);
}
return baos.toString("utf-8");
} catch (Exception e) {
throw new RequestErrorException(e);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (conn != null) {
conn.disconnect();
}
if (is != null)
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
if (baos != null) {
try {
baos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public static String get(String requestUrl) throws Exception {
HttpURLConnection conn = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
URL url = new URL(requestUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(CONNECT_TIMEOUT);
conn.setReadTimeout(READ_TIMEOUT);
conn.setDoInput(true);
conn.connect();
int code = conn.getResponseCode();
if (code != HttpURLConnection.HTTP_OK) {
throw new RespondErrorException(code);
}
is = conn.getInputStream();
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[BUF_SIZE];
int size;
while ((size = is.read(buffer)) != -1) {
baos.write(buffer, 0, size);
}
return baos.toString("utf-8");
} catch (Exception e) {
throw new RequestErrorException(e);
} finally {
if (conn != null) {
conn.disconnect();
}
if (is != null)
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
这个类需要解释的就是两个Exception,当http请求返回的状态码不为200时,抛出RespondErrorException,当http请求的过程中发生异常时,抛出RequestErrorException,这两个异常都是自定义的类,他们都继承自BaseException,而且带一个异常码,是枚举类型的。代码实现非常简单
package com.chenjian.net.exp;
/**
* http请求返回的StatusCode不为200
*
* 作者: ChenJian
* 时间: 2016.12.15 10:47
*/
public class RespondErrorException extends BaseException {
private int mRespondCode;
public RespondErrorException(int respondCode) {
super(ExceptionCode.EXPCODE_RESPOND_ERROR);
this.mRespondCode = respondCode;
}
public RespondErrorException() {
super(ExceptionCode.EXPCODE_RESPOND_ERROR);
}
public int getRespondCode() {
return mRespondCode;
}
public void setRespondCode(int respondCode) {
this.mRespondCode = respondCode;
}
}
package com.chenjian.net.exp;
/**
* http请求时发生异常
* <p>
* 作者: ChenJian
* 时间: 2016.12.15 10:59
*/
public class RequestErrorException extends BaseException {
public RequestErrorException(Exception e) {
super(e);
}
public RequestErrorException() {
super(ExceptionCode.EXPCODE_REQUEST_ERROR);
}
}
package com.chenjian.net.exp;
/**
* 自定义通用异常
* <p>
* 作者: ChenJian
* 时间: 2016.12.15 10:45
*/
public class BaseException extends Exception {
private ExceptionCode mCode;
public BaseException() {
}
public BaseException(Exception e) {
super(e);
}
public BaseException(ExceptionCode code) {
this.mCode = code;
}
public ExceptionCode getCode() {
return mCode;
}
public void setCode(ExceptionCode code) {
this.mCode = code;
}
}
package com.chenjian.net.exp;
/**
* 自定义异常码
* <p>
* 作者: ChenJian
* 时间: 2016.12.15 10:54
*/
public enum ExceptionCode {
/**
* http请求的过程中发生了异常
*/
EXPCODE_REQUEST_ERROR,
/**
* http请求返回的状态码不为200
*/
EXPCODE_RESPOND_ERROR,
}
接下来看看监听器基类NetListener
package com.chenjian.net.core.async;
/**
* 网络请求回调核心类
* <p>
* 作者: ChenJian
* 时间: 2016.12.13 17:42
*/
public interface NetListener {
/**
* http请求,数据解密部分,成功
*
* @param result result
*/
void sendSuccess(String result);
/**
* http请求,数据解密部分,失败
*
* @param e e
*/
void sendError(Exception e);
}
我们必须继承这个类,在回调sendSuccess时去做解析操作,于是就有了NetHandleListener
package com.chenjian.net.listener.async;
import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;
import com.chenjian.net.bean.NetRetBean;
import com.chenjian.net.core.async.NetListener;
import com.chenjian.net.exp.RequestErrorException;
import com.chenjian.net.exp.RespondErrorException;
import com.chenjian.net.listener.common.CallbackCode;
import org.json.JSONException;
import org.json.JSONObject;
import static com.chenjian.net.listener.common.CallbackCode.CODE_ERROR_JSON_EXP;
/**
* 公用网络逻辑,核心监听器。自定义监听器一般继承这个类
* <p>
* 作者: ChenJian
* 时间: 2016.12.15 11:12
*/
abstract public class NetHandleListener implements NetListener {
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
callbackResult((NetRetBean) msg.obj);
break;
}
}
};
private void callbackResult(NetRetBean netRetBean) {
onCommon();
switch (netRetBean.getCallbackCode()) {
case CODE_ERROR_HTTP_NOT_200:
case CODE_ERROR_REQUEST_EXP:
case CODE_ERROR_SERVER_DATA_ERROR:
case CODE_ERROR_JSON_EXP:
case CODE_ERROR_UNKNOWN:
onError(netRetBean.getCallbackCode(), netRetBean);
break;
case CODE_SUCCESS_REQUEST:
case CODE_SUCCESS_LOCAL:
onSuccess(netRetBean.getCallbackCode(), netRetBean);
break;
default:
break;
}
}
/**
* 将非ui线程处理结果传到ui线程去。是一个中转站。本类和其子类都可以调用这个方法
*
* @param netRetBean 要返回给ui线程的实体
*/
protected void handleResult(NetRetBean netRetBean) {
Message msg = Message.obtain();
msg.what = 1;
msg.obj = netRetBean;
mHandler.sendMessage(msg);
}
@Override
public void sendSuccess(String result) {
NetRetBean netRetBean = new NetRetBean();
try {
JSONObject jsonObject = new JSONObject(result);
String code = jsonObject.getString("code");
String message = jsonObject.getString("message");
String time = jsonObject.getString("time");
String data = jsonObject.getString("data");
netRetBean.setServerCode(code);
netRetBean.setServerMsg(message);
netRetBean.setServerTime(time);
netRetBean.setServerData(data);
if (code.equals("00001")) {
netRetBean.setCallbackCode(CallbackCode.CODE_SUCCESS_REQUEST);
onReceivedRet(netRetBean);
return;
} else {
netRetBean.setCallbackCode(CallbackCode.CODE_ERROR_SERVER_DATA_ERROR);
}
} catch (JSONException e) {
e.printStackTrace();
netRetBean.setCallbackCode(CODE_ERROR_JSON_EXP);
}
handleResult(netRetBean);
}
@Override
public void sendError(Exception exp) {
exp.printStackTrace();
NetRetBean netRetBean = new NetRetBean();
netRetBean.setException(exp);
try {
throw exp;
} catch (RespondErrorException e) {
netRetBean.setCallbackCode(CallbackCode.CODE_ERROR_HTTP_NOT_200);
} catch (RequestErrorException e) {
netRetBean.setCallbackCode(CallbackCode.CODE_ERROR_REQUEST_EXP);
} catch (JSONException e) {
netRetBean.setCallbackCode(CallbackCode.CODE_ERROR_JSON_EXP);
} catch (Exception e) {
netRetBean.setCallbackCode(CallbackCode.CODE_ERROR_UNKNOWN);
}
handleResult(netRetBean);
}
/**
* 子类根据业务区分,将netRetBean解析成list或者单个实体,或者解析成其它结果
*
* @param netRetBean server返回的数据实体,data字段将在子类中解析
* @throws JSONException 解析json异常
*/
abstract protected void onReceivedRet(NetRetBean netRetBean) throws JSONException;
/**
* ui线程中实现这个方法来得到网络请求返回的数据
*
* @param successCode 成功的code
* @param netRetBean 成功的实体bean,data字段已经在子类中解析完成
*/
abstract protected void onSuccess(CallbackCode successCode, NetRetBean netRetBean);
/**
* ui线程来处理错误码和错误信息
*
* @param errorCode 错误的code
* @param netRetBean 错误的实体bean,字段可能不完整(完整的话还是error吗?呵呵)
*/
abstract protected void onError(CallbackCode errorCode, NetRetBean netRetBean);
/**
* 运行在ui线程
* <p>
* 在onSuccess和onError之前都会调用这个方法。
* 子类可以重写,onSuccess和onError有大量重复代码时,只要在重写的onCommon方法里面执行就可以了
*/
protected void onCommon() {
}
}
不管是成功还是失败,都会根据不同的情况返回相应的CallbackCode。且最后调用onSuccess或者onError时候,都已经是在ui线程了。
这里还增加了onCommon方法,这个方法并不是abstract的,子类可以选择实现也可以不实现,就如注释所说,有时候在onSuccess和onError里面有重复代码时,我们只要重写onCommon,在里面写一次就够了。举个例子,在网络请求时需要进度条,请求后不管是成功还是失败都需要取消进度条,你不需要在onSuccess和onError里面把取消进度条的代码都写一次,你只需要实现onCommon,然后在里面写一次取消进度条的代码,就行了。
CallbackCode是一个枚举类型
package com.chenjian.net.listener.common;
/**
* 返回码
* <p>
* 作者: ChenJian
* 时间: 2016.12.15 11:31
*/
public enum CallbackCode {
/**
* 网络请求数据成功并解析成功
*/
CODE_SUCCESS_REQUEST,
/**
* 网络请求失败返回本地保存的数据(未实现)
*/
CODE_SUCCESS_LOCAL,
/**
* 网络请求失败,未知错误
*/
CODE_ERROR_UNKNOWN,
/**
* 网络请求失败,返回码不为200
*/
CODE_ERROR_HTTP_NOT_200,
/**
* 网络请求失败,请求过程当中异常了
*/
CODE_ERROR_REQUEST_EXP,
/**
* 服务器返回非成功数据,返回的code非00001
*/
CODE_ERROR_SERVER_DATA_ERROR,
/**
* 解析json出错
*/
CODE_ERROR_JSON_EXP,
}
结合NetHandleListener,可以很清楚的看出来,特别是在网络请求出错的情况下,能够给用户准确的CallbackCode,究竟是json解析异常,还是http请求状态码非200,还是请求时发生异常,还是code字段表示不成功。
不管是成功,还是失败,网络请求的结果都放到一个Bean里,他就是NetRetBean
package com.chenjian.net.bean;
import com.chenjian.net.listener.common.CallbackCode;
import java.util.Map;
/**
* 网络请求返回实体类
* <p>
* 作者: ChenJian
* 时间: 2016.12.14 16:02
*/
public class NetRetBean {
/**
* 返回码,具体说明请看{@link com.chenjian.net.listener.common.CallbackCode}
*/
private CallbackCode mCallbackCode;
/**
* 请求过程中发生异常,包括请求时,解析时。可能为null
*/
private Exception mException;
/**
* 服务端的返回码,是服务端返回的数据中解析“code”字段得到的。可能为null
*/
private String mServerCode;
/**
* 服务端返回的消息,是服务端返回的数据中解析“message”字段得到的。可能为null
*/
private String mServerMsg;
/**
* 服务端返回的时间,是服务端返回的数据中解析“time”字段得到的。可能为null
*/
private String mServerTime;
/**
* 服务端返回的数据,是服务端返回的数据中解析“data”字段得到的。可能为null
*/
private String mServerData;
/**
* 服务端返回的数据解析成的bean,是用mServerData字段进行json解析得到的。可能为null
*/
private Object mServerObject;
public NetRetBean() {
}
public boolean isSuccess() {
return mCallbackCode == CallbackCode.CODE_SUCCESS_REQUEST;
}
public CallbackCode getCallbackCode() {
return mCallbackCode;
}
public void setCallbackCode(CallbackCode callbackCode) {
this.mCallbackCode = callbackCode;
}
public Exception getException() {
return mException;
}
public void setException(Exception exception) {
this.mException = exception;
}
public String getServerCode() {
return mServerCode;
}
public void setServerCode(String serverCode) {
this.mServerCode = serverCode;
}
public String getServerMsg() {
return mServerMsg;
}
public void setServerMsg(String serverMsg) {
this.mServerMsg = serverMsg;
}
public String getServerTime() {
return mServerTime;
}
public void setServerTime(String serverTime) {
this.mServerTime = serverTime;
}
public String getServerData() {
return mServerData;
}
public void setServerData(String serverData) {
this.mServerData = serverData;
}
public Object getServerObject() {
return mServerObject;
}
public void setServerObject(Object object) {
this.mServerObject = object;
}
@Override
public String toString() {
return "NetRetBean{" +
"mCallbackCode=" + mCallbackCode +
", mException=" + mException +
", mServerCode='" + mServerCode + '\'' +
", mServerMsg='" + mServerMsg + '\'' +
", mServerTime='" + mServerTime + '\'' +
", mServerData='" + mServerData + '\'' +
", mServerObject=" + mServerObject +
'}';
}
}
讲到这里,公共部分的代码已经完成了,网络请求,解析外层数据,这些操作已经完成,内层数据的解析由下一篇来讲解。
可能有读者已经发现问题了,本篇中外层数据解析,并非通用的,笔者这里只是假设了外层数据字段有code,message,time,data,而且假设code为00001时才为正确。
当然,这都是笔者的假设,开发者可以根据自己的需求来修改,只要服务端返回的数据是下面这类结构的
{code, message, data : { 这里才是具体数据 } }
经过稍许修改就能成功运行。改的不仅仅是外层解析部分,NetRetBean里面的属性也要根据你的需要来修改。不过这两部分的代码跟其它模块无耦合,都是开发者根据自己的业务需求来修改的,所以改起来也相当容易。
所以,本框架是业务型框架,跟其它工具型框架不同的是,工具型框架是拿来直接使用的,像okhttp,gson之类的。业务型框架需要开发者手动修改一些代码。业务型框架可以跟工具型框架完全融合起来。笔者也考虑过通过配置的方法,让用户自己来实现外层解析,但那样的话框架代码太封闭了,Android是客户端,不像服务端,业务类型相对统一,比如JavaEE就有众多框架,通过自己的配置来使用的。关于这方面思想,在后面的总结章节里还会再讨论。
对于请求框架,比如okhttp,如果开发者需要,可以将HttpUtil里面的内容替换成okhttp,NetHelper里面的get和post再重载一些方法,加一些参数,可以在使用okhttp时做更多设置,最后由HttpUtil接收到设置,调用okhttp进行请求。返回时,也可以让NetRetBean更丰富一些。可以说,基本上只是HttpUtil里面的内容。因为笔者只是稍微了解过okhttp,可能见解比较浅,或者有错误,所以这里不再讲解。
对于解析框架,比如gson、fastjson本框架已经融合,后面的章节后讲到。
至此,公共部分代码实现已经讲解完成。
下一篇将讲解分支部分的代码实现,即内层数据解析部分