Android通用网络请求解析框架.4(代码实现,分支部分)

19 篇文章 0 订阅
14 篇文章 0 订阅
笔者将通过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) {

    }
});

有时候你并不关心返回结果,即使是返回失败了,你也不在乎。比如你只是做一些用户行为的上报。那么再对NetStringListener进行包装
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());


至此,整个框架基础的代码实现已经讲解完成。

下一篇将讲解框架的使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值