笔者将通过11篇博客对个人开源框架进行讲解,本篇为第4篇,讲解代码实现,分支部分。
如果有兴趣一起讨论本框架的内容,请加QQ群:271335749
上一篇中已经实现了公共部分的代码,网络请求,外层数据的解析。本篇将实现分支部分的代码,即内层数据的解析和泛型相关的处理。
再次回忆一下第一篇中分层解析的思想
abstract public class ParseJson {
private void parseJson(String jsonString) throws JSONException {
JSONObject jsonObject = new JSONObject(jsonString);
String code = jsonObject.getString("code");
String message = jsonObject.getString("message");
Object data = parseData(jsonObject.getString("data"));
}
abstract Object parseData(String jsonString) throws JSONException;
}
父类实现外层数据解析,内层数据,根据不同的业务,实现不同的子类,看看最终的实现。这里只贴上部分代码
abstract public class NetHandleListener implements NetListener {
@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);
}
/**
* 子类根据业务区分,将netRetBean解析成list或者单个实体,或者解析成其它结果
*
* @param netRetBean server返回的数据实体,data字段将在子类中解析
* @throws JSONException 解析json异常
*/
abstract protected void onReceivedRet(NetRetBean netRetBean) throws JSONException;
}
如果data里面所对应的数据是单个Bean,我们就在子类中进行单个Bean的解析。于是,我们继承NetHandleListener,实现NetSingleBeanListener
package com.chenjian.net.listener.async;
import com.chenjian.net.bean.NetBaseBean;
import com.chenjian.net.bean.NetRetBean;
import com.chenjian.net.listener.common.CallbackCode;
import com.chenjian.net.util.NetBaseBeanUtil;
import org.json.JSONException;
import org.json.JSONObject;
/**
* 返回是单个Bean的网络请求Listener
* <p>
* 作者: ChenJian
* 时间: 2016.12.15 14:54
*/
abstract public class NetSingleBeanListener<T extends NetBaseBean> extends NetHandleListener {
@Override
protected void onReceivedRet(NetRetBean netRetBean) throws JSONException {
JSONObject object = new JSONObject(netRetBean.getServerData());
T t = NetBaseBeanUtil.parseItem(getClass(), 0, object);
netRetBean.setServerObject(t);
handleResult(netRetBean);
}
@SuppressWarnings("unchecked")
@Override
protected void onSuccess(CallbackCode successCode, NetRetBean netRetBean) {
onSuccess((T) netRetBean.getServerObject());
}
/**
* 运行在ui线程,返回单个实体
*
* @param t 当前bean
*/
abstract protected void onSuccess(T t);
}
handleResult调用的是父类的方法,通过中转站把数据返回到主线程。
开发者在使用NetSingleBeanListener,回调onSuccess(T t)时,参数是已经强转好的了,而且是不为null的。
onReceivedRet方法是可能抛出异常的,这里抛出的是json异常,因为可能在NetBaseBeanUtil.parseItem中,发生了异常。
parseItem方法传入了三个参数,Class对象,0,还有JsonObject。想要知道三个参数的意思,进去看看
package com.chenjian.net.util;
import com.chenjian.net.bean.NetBaseBean;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.reflect.ParameterizedType;
/**
* NetBaseBean工具类,实现对泛型进行创建实例,并进行解析
* <p>
* 作者: ChenJian
* 时间: 2016.12.15 14:22
*/
public class NetBaseBeanUtil {
/**
* @param aClass 带泛型 T 的类,应该传入xxBeanListener监听器或其的子类。他的父类必须是带泛型T的
* @param tIndex 泛型 T 所在下标
* @param jsonObject 用来解析的 json
* @param <T> 泛型 T
* @return 返回泛型T的实例
* @throws JSONException
*/
public static <T extends NetBaseBean> T parseItem(Class aClass, int tIndex, JSONObject jsonObject) throws JSONException {
T t = getBean(aClass, tIndex);
t.initByJson(jsonObject);
return t;
}
/**
* @param aClass 带泛型 T 的类,应该传入xxBeanListener监听器或其的子类。他的父类必须是带泛型T的
* @param tIndex 泛型 T 所在下标
* @param <T> 泛型 T
* @return 返回泛型T的实例
*/
@SuppressWarnings("unchecked")
private static <T extends NetBaseBean> T getBean(Class aClass, int tIndex) {
Class<T> entityClass = (Class<T>) ((ParameterizedType) aClass.getGenericSuperclass()).getActualTypeArguments()[tIndex];
T entity = null;
try {
// 使用newInstance创建实例的类,必须有无参构造方法
entity = entityClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return entity;
}
}
这个类中,先是利用反射的方法,创建出泛型的实例,aClass必须是NetSingleBeanListener的子类,tIndex是泛型所在数组下标,因为aClass带的泛型可能不只一个,比如xxCustomBeanListener<A, B, C>,你要创建泛型B的实例,就传入泛型B的下标,这里是1。泛型C的下标对应的是2。而NetSingleBeanListener只有一个泛型T,所以传入0即可。
创建完实例后,再通过initByJson方法进行解析,这个方法来自NetBaseBean,所以T也必须是继承NetBaseBean。本类的类名是NetBaseBeanUtil,也是由此而来。
NetBaseBean中又有哪些内容?
package com.chenjian.net.bean;
import org.json.JSONException;
import org.json.JSONObject;
/**
* 网络请求解析实体基类。子类必须有无参构造方法
* <p>
* 作者: ChenJian
* 时间: 2016.12.13 15:48
*/
abstract public class NetBaseBean {
/**
* 子类实现这个方法,在其中解析json
*
* @param jsonObject 将要解析的JsonObject
* @throws JSONException
*/
abstract public void initByJson(JSONObject jsonObject) throws JSONException;
}
一个抽象类,子类必须实现这个方法,在其中解析json。既然要在这个方法中进行解析,所以他是可能抛出异常的。
一起来梳理一下异常抛出最后在哪里被接收了吧。这也是一个有趣的过程。
NetBaseBean.initByJson-->NetBaseBeanUtil.parseItem
NetBaseBeanUtil.parseItem-->NetSingleBeanListener.onReceivedRet
NetSingleBeanListener.onReceivedRet-->NetHandleListener.sendSuccess
在NetHandleListener.sendSuccess里,我们try catch掉了异常,
在catch里,设置了netRetBean.setCallbackCode(CODE_ERROR_JSON_EXP)
然后再通过handleResult方法返回到主线程,
主线程中判断CallbackCode为CODE_ERROR_JSON_EXP,就调用onError方法,并将错误码在onError方法中回调给开发者
至此,完成了一套内层解析,也就是NetSingleBeanListener这个类,他可以解析单个Bean。
再假设服务端返回的数据是这样的:
{
"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线程
}
});
这里使用的时候,是用内部类的方法,开发者们最熟悉不过了,比如view.setOnClickListener(new OnClickListener)。
内部类的方式,实际上编译器也会先定义一个类,他继承NetSingleBeanListener,然后再把这个类当成参数传进去。
也一起来梳理一下网络请求的数据传递和回调的过程,同样相当有趣。
定义一个类,就他叫MyListener吧,继承自NetSingleBeanListener。这一步是编译器帮你完成的。
MyListener实现了两个抽象方法
将url和MyListener传入NetHelper.get方法
NetHelper.get方法开始调用NetExcutor进行请求
NetExcutor请求失败将回调sendError
sendError将保存错误信息并传给ui线程
ui线程回调onError方法,即MyListener的onError方法
NetExcutor请求成功将回调sendSuccess
sendSuccess里面对外层数据进行解析
sendSuccess把未解析的内层数据丢给onReceivedRet,让子类来解析
NetSingleBeanListener.onReceivedRet中对内层数据进行解析
NetSingleBeanListener.onReceivedRet把解析后的数据通过父类的handleResult传给ui线程
ui线程通过CallbackCode判断为解析成功
ui线程回调onSuccess方法,即NetSingleBeanListener中被实现的那个onSuccess方法
NetSingleBeanListener中被实现的那个onSuccess方法调用未被实现的抽象方法onSuccess,即MyListener的onSuccess方法
至此,MyListener得到了Bean
这里,还要回顾一个非常重要的知识,MyListener是NetSingleBeanListener的子类,如果在MyListener的OnReceivedRet中进行getClass()的时候,其实得到的是MyListener,而不是NetSingleBeanListener。所以再看看NetBaseBeanUtil里面的getBean()方法,其aClass就是MyListener,进行了getGenericSuperclass调用,调用之后得到的正是NetSingleBeanListener。如果aClass是NetSingleBeanListener,调用GetGenericSuperclass后得到的是NetHandleListener,而NetHandleListener并没有带泛型,getBean方法就会出错。这一切都是因为java泛型的去参数化的原因,在后面的同步请求章节中,会比较详细的讲解。
看起来已经完成得差不多了。
但是这永远不够,因为服务端返回的内层数据不一定会是单个Bean的,也可能是多个Bean的,是一个json的数组
{
"code":"00001",
"message":"login success",
"time":"1479807260",
"data":[
{
"id":"123",
"name":"chenjian"
},
{
"id":"123",
"name":"chenjian"
},
{
"id":"123",
"name":"chenjian"
}
]
}
这个时候,模仿NetSingleBeanListener,再实现一套将json数组解析成List<Bean>的监听器即可。于是,NetListBeanListener诞生了
package com.chenjian.net.listener.async;
import com.chenjian.net.bean.NetBaseBean;
import com.chenjian.net.bean.NetRetBean;
import com.chenjian.net.listener.common.CallbackCode;
import com.chenjian.net.util.NetBaseBeanUtil;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
/**
* 返回是List<Bean>的网络请求Listener
* <p>
* 作者: ChenJian
* 时间: 2016.12.15 14:54
*/
abstract public class NetListBeanListener<T extends NetBaseBean> extends NetHandleListener {
@Override
protected void onReceivedRet(NetRetBean netRetBean) throws JSONException {
JSONArray array = new JSONArray(netRetBean.getServerData());
List<T> list = new ArrayList<>();
for (int i = 0; i < array.length(); i++) {
JSONObject object = array.getJSONObject(i);
T t = NetBaseBeanUtil.parseItem(getClass(), 0, object);
list.add(t);
}
netRetBean.setServerObject(list);
handleResult(netRetBean);
}
@SuppressWarnings("unchecked")
@Override
protected void onSuccess(CallbackCode successCode, NetRetBean netRetBean) {
onSuccess((List<T>) netRetBean.getServerObject());
}
/**
* 运行在ui线程,返回多个实体
*
* @param ts 当前bean的List
*/
abstract protected void onSuccess(List<T> ts);
}
NetSingleBeanListener是把data里面当成普通json,NetListBeanListener则是当成JsonArray来解析,再对Array里面的每一个Json通过NetBaseBeanUtil.parseItem进行解析,最后存入serverObject里面的不是泛型T,而是List<T>。当然,成功时候进行强转,也要转成List<T>。
使用时,也是如此简单
NetHelper.get("url", new NetListBeanListener<NetUserBean>() {
@Override
protected void onError(CallbackCode errorCode, NetRetBean netRetBean) {
}
@Override
protected void onSuccess(List<NetUserBean> netUserBeen) {
}
});
当然。data中的数据也可能是简单的字符串,你不打算为他定义一个Bean
{
"code":"00001",
"message":"login success",
"time":"1479807260",
"data":"hello world"
}
于是,再为你实现一个监听器,返回的是String
package com.chenjian.net.listener.async;
import com.chenjian.net.bean.NetRetBean;
import com.chenjian.net.listener.common.CallbackCode;
import org.json.JSONException;
/**
* 返回字String的网络请求Listener
* <p>
* 作者: ChenJian
* 时间: 2016.12.15 14:54
*/
abstract public class NetStringListener extends NetHandleListener {
@Override
protected void onReceivedRet(NetRetBean netRetBean) throws JSONException {
netRetBean.setServerObject(netRetBean.getServerData());
handleResult(netRetBean);
}
@SuppressWarnings("unchecked")
@Override
protected void onSuccess(CallbackCode successCode, NetRetBean netRetBean) {
onSuccess((String) netRetBean.getServerObject());
}
/**
* 运行在ui线程,返回单个实体
*
* @param string 当前string
*/
abstract protected void onSuccess(String string);
}
使用起来并没有太大的差别
NetHelper.get("url", new NetStringListener() {
@Override
protected void onSuccess(String string) {
}
@Override
protected void onError(CallbackCode errorCode, NetRetBean netRetBean) {
}
});
package com.chenjian.net.listener.async;
import com.chenjian.net.bean.NetRetBean;
import com.chenjian.net.listener.common.CallbackCode;
/**
* 作者: ChenJian
* 时间: 2016.12.20 14:50
*/
public class NetTempListener extends NetStringListener {
@Override
protected void onSuccess(String string) {
}
@Override
protected void onError(CallbackCode errorCode, NetRetBean netRetBean) {
}
}
因为这个监听器已经不是抽象类,父类的抽象方法他也都实现了,所以使用起来只要一行代码
NetHelper.get("url", new NetTempListener());
至此,整个框架基础的代码实现已经讲解完成。
下一篇将讲解框架的使用