Android通用网络请求解析框架.6(自定义解析器)
来源:互联网 发布:淘宝airbnb优惠靠谱吗 编辑:程序博客网 时间:2024/05/20 23:58
笔者将通过11篇博客对个人开源框架进行讲解,本篇为第6篇,讲解自定义解析器。
开源库github地址 https://github.com/qq296216078/Android-Universial-NetFrame
如果有兴趣一起讨论本框架的内容,请加QQ群:271335749
上一篇中讲解了使用框架,对于不同格式的数据返回,我们可以选择不同的Listener,最后也总结出了NetStringListener是万能的。
其实一些时候,服务端返回的数据不一定是单个Bean或者List<Bean>格式的。
现在我们来看看下面这种情况
{ "code":"00001", "message":"login success", "time":"1479807260", "data":{ "list":[ { "id":"123", "name":"chenjian" }, { "id":"123", "name":"chenjian" }, { "id":"123", "name":"chenjian" } ], "page":"1", "page_size":"3", "total":"3" }}
这个时候,NetListBeanListener不能使用了,因为data里面存放的不是JsonArray,
在NetListBeanListener的OnReceivedRet方法里面的第一行,
JSONArray array = new JSONArray(netRetBean.getServerData());
就会抛出JSONException。
要怎么办?和上面所说的一样,你可以使用NetStringListener,在onSuccess方法里面再进行解析。但这样做显然不合理。
仔细想想,这里其实多了一个办法,也就是可以使用NetSingleBeanListener。怎么做呢?我们需要定义一个Bean
public class NetFriendBean extends NetBaseBean { private String page; private String pageSize; private String total; private List<NetUserBean> mNetUserBeen; @Override public void initByJson(JSONObject jsonObject) throws JSONException { this.page = jsonObject.getString("page"); this.pageSize = jsonObject.getString("page_size"); this.total = jsonObject.getString("total"); this.mNetUserBeen = new ArrayList<>(); JSONArray jsonArray = jsonObject.getJSONArray("list"); for (int i = 0; i < jsonArray.length(); i++) { NetUserBean netUserBean = new NetUserBean(); netUserBean.initByJson(jsonArray.getJSONObject(i)); mNetUserBeen.add(netUserBean); } }}
在NetFriendBean中,前三个字段我们正常解析,最后一个数组,我们利用了NetUserBean来解析,NetUserBean的代码与之前一样
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"); }}
于是你就可以正常使用了
NetHelper.get("url", new NetSingleBeanListener<NetFriendBean>() { @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { } @Override protected void onSuccess(NetFriendBean netFriendBean) { }});
public class NetPageBean extends NetBaseBean { private String page; private String pageSize; private String total; @Override public void initByJson(JSONObject jsonObject) throws JSONException { this.page = jsonObject.optString("page"); this.pageSize = jsonObject.optString("page_size"); this.total = jsonObject.optString("total"); }}
然后NetFriendBean就可以修改成更简洁的样子
public class NetFriendBean extends NetBaseBean { private NetPageBean mNetPageBean; private List<NetUserBean> mNetUserBeen; @Override public void initByJson(JSONObject jsonObject) throws JSONException { this.mNetPageBean = new NetPageBean(); this.mNetPageBean.initByJson(jsonObject); this.mNetUserBeen = new ArrayList<>(); JSONArray jsonArray = jsonObject.getJSONArray("list"); for (int i = 0; i < jsonArray.length(); i++) { NetUserBean netUserBean = new NetUserBean(); netUserBean.initByJson(jsonArray.getJSONObject(i)); mNetUserBeen.add(netUserBean); } }}
在使用部分,还是原来的样子
NetHelper.get("url", new NetSingleBeanListener<NetFriendBean>() { @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { } @Override protected void onSuccess(NetFriendBean netFriendBean) { }});
这样有个好处就是NetPageBean可以共用,如果还有其它的服务端请求有返回那三个字段,在Bean里加一个NetPageBean的属性就行了。
很愉快吧,毕竟本框架叫 Android通用网络请求解析框架 ,通用性还是很强的。
但是问题出现了,我们平常项目中,会经常出现非常多的列表请求,就算前三个字段不变,后面的list数据变成其它的Bean,你的NetFriendBean就不能用了。也就是说,出现一个列表,你就要重新写一个Bean,然后用NetSingleBeanListener来请求解析。这是多么的蛋疼啊!
那有没有办法解决呢?显然是有的,也就是自定义解析器。
既然NetSingleBeanListener不适合,而NetListBeanListener不能使用,因为data里面的数据不是JsonArray,那我们就自己实现一个Listener。
要怎么做呢?这两个Listener不能用,而又要学他们,那就从继承学起,也继承NetHandleListener,在其中,我们需要解析一个NetPageBean,再解析一个List<NetUserBean>,返回给用户时,也不止一个参数了,而是NetPageBean和List<NetUserBean>。直接看代码吧
package com.chenjian.net.demo.listener.async;import com.chenjian.net.bean.NetBaseBean;import com.chenjian.net.bean.NetRetBean;import com.chenjian.net.listener.async.NetHandleListener;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.HashMap;import java.util.List;import java.util.Map;/** * 作者: ChenJian * 时间: 2016.12.16 13:51 */abstract public class NetCustomBeanListener<Page extends NetBaseBean, T extends NetBaseBean> extends NetHandleListener { @Override protected void onReceivedRet(NetRetBean netRetBean) throws JSONException { JSONObject jsonObject = new JSONObject(netRetBean.getServerData()); Page page = NetBaseBeanUtil.parseItem(getClass(), 0, jsonObject); List<T> list = new ArrayList<>(); JSONArray jsonArray = jsonObject.getJSONArray("list"); for (int i = 0; i < jsonArray.length(); i++) { JSONObject object = jsonArray.getJSONObject(i); T t = NetBaseBeanUtil.parseItem(getClass(), 1, object); list.add(t); } Map<String, Object> map = new HashMap<>(); map.put("page", page); map.put("list", list); netRetBean.setServerObjectMap(map); handleResult(netRetBean); } @SuppressWarnings("unchecked") @Override protected void onSuccess(CallbackCode successCode, NetRetBean netRetBean) { Map<String, Object> map = netRetBean.getServerObjectMap(); onSuccess((Page) map.get("page"), (List<T>) map.get("list")); } /** * 运行在ui线程,返回多个实体 * * @param ts 当前bean的List */ abstract protected void onSuccess(Page page, List<T> ts);}
在onReceivedRet方法中,我们不把数据当成是单个Bean,也不当成List<Bean>来解析,而是当成一个Bean和一个List<Bean>来解析,在onSuccess方法中,我们回调给开发者的时候,也是开发者传入的两个泛型。在这里,我们用到了NetRetBean的getServerObjectMap和setServerObjectMap方法,其实只是在NetRetBean里面加了一个属性,
并实现了他的get和set方法。
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 { /** * 自定义监听器时使用。服务端返回的数据解析,可能有多个bean,是用mServerData字段进行json解析得到的。可能为null */ private Map<String, Object> mServerObjectMap; public NetRetBean() { } public Map<String, Object> getServerObjectMap() { return mServerObjectMap; } public void setServerObjectMap(Map<String, Object> serverObjectMap) { this.mServerObjectMap = serverObjectMap; }}
还看到对于Page,我们解析的时候的代码是
Page page = NetBaseBeanUtil.parseItem(getClass(), 0, jsonObject);
T t = NetBaseBeanUtil.parseItem(getClass(), 1, object);
因为Page是泛型列表里面的第0个,T是第1个,之前NetBaseBeanUtil的parseItem方法的第二个参数,在这里终于用上了。
NetHelper.get("url", new NetCustomBeanListener<NetPageBean, NetUserBean>() { @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { } @Override protected void onSuccess(NetPageBean netPageBean, List<NetUserBean> netUserBeen) { }});
开发者在这里多实现了一个Listener,好像并不比之前的定义一个NetFriendBean来得简单多少,这样的方案或许到现在还不能打动你。
但这个时候,如果有另一个网络请求,他返回的数据是这样的
{ "code":"00001", "message":"login success", "time":"1479807260", "data":{ "list":[ { "title":"title1", "desc":"desc1", "date":"date1" }, { "title":"title2", "desc":"desc2", "date":"date2" }, { "title":"title3", "desc":"desc3", "date":"date3" } ], "page":"1", "page_size":"3", "total":"3" }}
你只需要定义一个Bean
public class NetInfoBean extends NetBaseBean { private String infoTitle; private String infoDesc; private String infoDate; @Override public void initByJson(JSONObject jsonObject) throws JSONException { this.infoTitle = jsonObject.getString("title"); this.infoDesc = jsonObject.getString("desc"); this.infoDate = jsonObject.getString("date"); }}
就也可以使用NetCustomBeanListener了
NetHelper.get("url", new NetCustomBeanListener<NetPageBean, NetInfoBean>() { @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { } @Override protected void onSuccess(NetPageBean netPageBean, List<NetInfoBean> netInfoBeen) { }});
可以看出,你的项目中存在多个或者大量的相似格式的网络请求返回,而此时默认的NetSingleBeanListener和NetListBeanListener不能解决你问题,自定义解析器就派上用场了。此处关于自定义解析器,只是举个例子,开发者在使用时,可以根据自己的需求来实现不同的自定义解析器。
其实本例中的自定义解析器,还有另一种做法,也就是修改NetFriendBean,改成这样
public class NetCustomBean<T extends NetBaseBean> extends NetBaseBean { private NetPageBean mNetPageBean; private List<T> mTList; @Override public void initByJson(JSONObject jsonObject) throws JSONException { this.mNetPageBean = new NetPageBean(); this.mNetPageBean.initByJson(jsonObject); this.mTList = new ArrayList<>(); JSONArray jsonArray = jsonObject.getJSONArray("list"); for (int i = 0; i < jsonArray.length(); i++) { T t = NetBaseBeanUtil.parseItem(getClass(), 0, jsonArray.getJSONObject(i)); mTList.add(t); } } public NetPageBean getNetPageBean() { return mNetPageBean; } public void setNetPageBean(NetPageBean netPageBean) { this.mNetPageBean = netPageBean; } public List<T> getTList() { return mTList; } public void setTList(List<T> tList) { this.mTList = tList; }}
使用起来是这样的
NetHelper.get("url", new NetSingleBeanListener<NetCustomBean<NetUserBean>>() { @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { } @Override protected void onSuccess(NetCustomBean<NetUserBean> netUserBeanNetCustomBean) { NetPageBean netPageBean = netUserBeanNetCustomBean.getNetPageBean(); List<NetUserBean> netUserBeen = netUserBeanNetCustomBean.getTList(); }});
可以使用NetSingleBeanListener了。但笔者认为,这样在结构上会很混乱,嵌套多层泛型的时候,代码不容易读懂且容易出错。所以笔者推荐使用自定义解析器的方式,而不是在Bean里面把代码做得复杂。
关于更多自定义解析器的使用,可以参考源码中的CustomActivity。
至此,自定义解析器已经讲解完了,看完这一篇,开发者已经可以在自己的项目中自由的使用本框架了。
下一篇将讲解同步请求公共部分
Android通用网络请求解析框架.7(同步请求,公共部分)
0 0
- Android通用网络请求解析框架.6(自定义解析器)
- Android通用网络请求解析框架.2(构造框架)
- Android通用网络请求解析框架.5(使用框架)
- Android通用网络请求解析框架.1(需求,思想)
- Android通用网络请求解析框架.11(总结)
- Android通用网络请求解析框架.9(支持第三方解析框架)
- Android通用网络请求解析框架.7(同步请求,公共部分)
- Android通用网络请求解析框架.8(同步请求,分支部分)
- Android通用网络请求解析框架.3(代码实现,公共部分)
- Android通用网络请求解析框架.4(代码实现,分支部分)
- Android通用网络请求解析框架.10(发现问题,改善)
- Android网络请求框架----Okhttp3完全解析(2),封装框架
- Android网络请求框架—OKHttp 源码解析
- Android网络请求框架Velley的用法与解析
- android网络请求全面解析
- Android网络请求框架----Okhttp3完全解析(1),使用篇
- 【框架】网络请求+Gson解析--Retrofit 2
- OkHttp网络请求框架+AsyncTask自动解析
- JAVA 取得当前目录的路径/Servlet/class/文件路径/web路径/url地址
- Flex air修改外部xml文件 (转)
- mysql-5.7.13-win32 安装
- 正则表达式之量词与匹配模式
- spring+mybatis返回json日期处理(日期全局处理相差8个小时解决方法)
- Android通用网络请求解析框架.6(自定义解析器)
- jquery 模拟点击 a 连接
- 哈哈 我什么也不知道
- Elasticsearch自定义插件开发
- 2016总结——在路上,我走到哪儿了?
- php5.6新特性
- windows系统oracle数据导入
- Spring mvc+freeMarker 使用jsp自定义标签
- SpringMVC注解说明