美文网首页Android安卓网络
封装网络框架时,如何优雅的传参?

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

作者: CDF_cc7d | 来源:发表于2019-01-30 20:34 被阅读407次

前言

我相信大家对于网络框架的使用选择已经是驾轻就熟了。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<String,LoginBean> {
    /**
     * 登录账号
     */
    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<ILoginContract.ILoginView> 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<LoginBean> mLoginCB = new NetworkCallBack<LoginBean>() {
        @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层的成员变量就可以了,而且不需要再传入参数,设计优雅,使用简单。

相关文章

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

    前言 我相信大家对于网络框架的使用选择已经是驾轻就熟了。OKhttp,Retrofit,Volley,NoHttp...

  • Retrofit源码分析

    本文概述Retrofit作为主流的网络框架,采用注解和接口的方式封装请求,使得调用过程变得优雅又简洁,优雅的背后肯...

  • 图片加载框架的封装

    如何正确的使用图片加载框架? 封装!!! 别在图片需要加载时直接使用图片加载框架应该封装这个框架之后再间接使用 比...

  • iOS网络框架简单封装

    AFN 简单封装--iOS重构-轻量级的网络请求封装实践 YTKNetworking 网络框架封装源码解析:网络层...

  • jq地址栏传参与接收参数

    传参文件: 接收参数: 自己封装的扩展文件(jqExpand):

  • flutter网络请求封装

    Flutter 网络请求框架封装

  • 如何限制别人传递的字典类型参数的key

    在封装SDK时,只能限制开发者传参的类型,而不能限制传递参数的内容。 例如-(void)tranwithDic:(...

  • iOS AFNetworking传参不带key解决办法

    POST请求,JAVA后台,个别接口传参要求传JSON数据,并且不带key的那种…… 如果你的网络框架也是AFNe...

  • 2018-09-26 vue.js

    1、查询字符串 传参时书写格式: 接收时书写格式: 2、rest风格传参 传参时书写格式: 接收时书写格式: 例:...

  • 路由的传参

    1、查询字符串 传参时书写格式: 接收时书写格式: 2、rest风格传参 传参时书写格式: 接收时书写格式: 例:

网友评论

    本文标题:封装网络框架时,如何优雅的传参?

    本文链接:https://www.haomeiwen.com/subject/gjbcsqtx.html