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) {                    }});

如果你觉得那三个单独的字段也应该进行封装,那么再定义一个Bean
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 t = NetBaseBeanUtil.parseItem(getClass(), 1, object);

因为Page是泛型列表里面的第0个,T是第1个,之前NetBaseBeanUtil的parseItem方法的第二个参数,在这里终于用上了。


如果使用NetCustomBeanListener,Page传入的是PageBean,T传入的是NetUserBean的话,那么使用起来就会是这样
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
原创粉丝点击