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

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



再来看看NetExcutor
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 +
                '}';
    }
}

只有mCallbackCode是每次都有值的,其它的都可能为null,因为可能失败,而成功的时候mException为null。


讲到这里,公共部分的代码已经完成了,网络请求,解析外层数据,这些操作已经完成,内层数据的解析由下一篇来讲解。
可能有读者已经发现问题了,本篇中外层数据解析,并非通用的,笔者这里只是假设了外层数据字段有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本框架已经融合,后面的章节后讲到。


至此,公共部分代码实现已经讲解完成。

下一篇将讲解分支部分的代码实现,即内层数据解析部分
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值