前言
我相信大家对于网络框架的使用选择已经是驾轻就熟了。OKhttp,Retrofit,Volley,NoHttp等等网上一系列优秀的框架,这里不讨论网络框架的选择,另外对于网络框架进行二次封装也基本上是信手拈来的事,所以这里也不加讨论。本文只介绍如何优雅的传参。
对于网络框架传参,我想大部分人都会有三种做法:
- 直接通过方法将所有参数一起传入
- 通过set方法将参数逐个传入model中
- 新建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层的成员变量就可以了,而且不需要再传入参数,设计优雅,使用简单。