封装网络框架时,如何优雅的传参?

前言

我相信大家对于网络框架的使用选择已经是驾轻就熟了。OKhttp,Retrofit,Volley,NoHttp等等网上一系列优秀的框架,这里不讨论网络框架的选择,另外对于网络框架进行二次封装也基本上是信手拈来的事,所以这里也不加讨论。本文只介绍如何优雅的传参。


对于网络框架传参,我想大部分人都会有三种做法:

  1. 直接通过方法将所有参数一起传入
  2. 通过set方法将参数逐个传入model中
  3. 新建Request实体类,将参数传入实体类中,然后将实体类传入到网络请求框架中。

那么我们先介绍这几种的优缺点:

「1. 直接通过方法将所有参数一起传入」
    /**
     * 登录
     * @param account 账号
     * @param password 密码
     */
    public void login(String account,String password){
        //执行网络请求的操作
    }
    new LoginApi().login("账号","密码");

如上述代码所示,直接将参数传入。
优点:设计简单。
缺点:1.方法直接传入参数,每次更改参数类型或者数量时,自己封装的网络框架的方法都需要修改。(特别对于组件化开发及其不方便)2.如果参数数量很多,十个或者几十个参数时,那么此方法将会非常长,代码也就变得很难看。

「2. 通过set方法将参数逐个传入model中」
public class LoginApi extends ApiModel {
    /**
     * 登录账号
     */
    private String mMobile;
    /**
     * 登录密码
     */
    private String mPassword;
    @Override
    protected void request() {
        //进行网络请求
    }

    @Override
    protected boolean isNeedEncrypt() {
        return true;
    }

    /**
     * 设置手机号
     * @param mobile 手机号
     * @return LoginApi
     */
    public LoginApi setMobile(String mobile){
        mMobile = mobile;
        return this;
    }

    /**
     * 设置密码
     * @param password 密码
     * @return LoginApi
     */
    public LoginApi setPassword(String password){
        mPassword = password;
        return this;
    }

}
new LoginApi().setMobile("账号").setPassword("密码").request();

优点:采用链式设计结构代码优雅美观
缺点:1.方法通过set传入,每次后台更改参数类型或者参数数量,都需要需改自己封装的网络框架(特别对于组件化开发及其不方便)。

「3. 新建Request实体类,将参数传入实体类中,然后将实体类传入到网络请求框架中。」
    /**
     * 登录请求
     * @param request 请求
     */
    public void login(LoginRequest request){
        //进行网络请求
    }
LoginRequest request = new LoginRequest();
request.setAccount("账号");
request.setPassword("密码");
new LoginApi().login(request);

优点:易于修改参数类型,参数个数,设计比较优雅。
缺点:每次在调用封装的网络框架接口时,都需要事先封装一个实体类,然后将实体类传入,而且每个接口都需要设计一个对应的实体类,操作复杂。

以上三种方法都有各自的优缺点,那么是否存在着一种方式可以包含上述所有的优点,而没有上面的缺点呢?答案自然是肯定的。


其实上述的几种方式都是考虑的如何将参数传入,所以思维就固定住了。我们不妨反过来思考,封装的网络框架该如何获取对应的参数?
看到这,我想不少人会疑惑,怎么获取?那么请往下看。

public class LoginPresenter extends BasePresenter implements ILoginContract.ILoginPresenter {
    @HttpConfig(httpApi = LoginApi.class)
    private String mobile;
    @HttpConfig(httpApi = LoginApi.class)
    private String passwd;
    @Inject
    public LoginPresenter() {

    }

    @Override
    public void login(String account, String pwd) {
        this.mobile = account;
        this.passwd = pwd;
        new LoginApi(this).setCallback(mLoginCB).needRequest().showProgress().request();
    }

    private NetworkCallBack mLoginCB = new NetworkCallBack() {
        @Override
        public void OnSuccess(boolean b, ResponseBean responseBean, LoginBean loginBean) {
             //登录成功回调
        }

        @Override
        public void OnFail(boolean b, String s, boolean b1) {
            //登录失败回调
        }
    };
}

上面是业务层代码,调用model层的网络接口时,并没有传入参数。这是为何?
关键就在于将参数作为presenter的成员变量,并给参数设置注解。那么该如何自定义注解才能化腐朽为神奇呢?请看以下代码

        if(mIsRequest){
            JsonObject jsonObject = new JsonObject();
            Field[] fields = mObj.getClass().getDeclaredFields();//获取该对象所有成员变量
            int pageIndex = -1;
            int pageSize = -1;
            for (Field field : fields) {
                HttpConfig config = field.getAnnotation(HttpConfig.class);//获取该成员变量的HttpConfig注解
                if(config == null){
                    continue;
                }
                Class[] clazz = config.httpApi();//获取该注解的class数组
                try {
                    for (Class cls : clazz) {//循环class数组
                        if (cls.getName().equals(getClass().getName())) {
                            //当class的名字与当前api类名字相同时,意味着将参数传入到当前api类中
                            String param = field.getName();//成员变量的名字即网络请求参数名
                            if (param.equals("pageSize")) {
                                pageIndex = (int) field.get(mObj);
                                break;
                            }
                            if (param.equals("pageIndex")) {
                                pageSize = (int) field.get(mObj);
                                break;
                            }
                            field.setAccessible(true);
                            if(field.get(mObj) != null){//成员变量不为null时,将变量添加到jsonObject中
                                switch (field.getType().getName()) {
                                    case "java.lang.Boolean":
                                        jsonObject.addProperty(param, (Boolean) field.get(mObj));
                                        break;
                                    case "java.lang.Character":
                                        jsonObject.addProperty(param, (Character) field.get(mObj));
                                        break;
                                    case "java.lang.Integer":
                                    case "java.lang.Double":
                                    case "java.lang.Float":
                                    case "java.lang.Long":
                                    case "java.lang.Byte":
                                    case "java.lang.Short":
                                        jsonObject.addProperty(param, (Number) field.get(mObj));
                                        break;
                                    case "java.lang.String":
                                    default:
                                        jsonObject.addProperty(param, (String) field.get(mObj));
                                        break;
                                }
                            }
                            break;
                        } else if (cls.getName().equals("java.lang.Object")) {
                            break;
                        }
                    }
                } catch (IllegalAccessException e) {
                    LogUtil.e("e = " + e);
                }
            }

在new出loginApi的model时将presenter传入,然后在model中将presenter的成员变量全部获取到,然后选取注解为loginAPI的成员变量,设置成一个json对象。
这样不管后台怎么更改参数类型或者是参数数量,只要修改p层的成员变量就可以了,而且不需要再传入参数,设计优雅,使用简单。

你可能感兴趣的:(封装网络框架时,如何优雅的传参?)