Skip to content

高级功能

liujingxing edited this page Feb 25, 2023 · 19 revisions

自定义Parser

通过自定义Parser,我们可以非常方便的解析Response<T>类型数据,并统一对code做判断,数据结构如下:

public class Response<T> {
    private int    code;
    private String msg;
    private T      data;
    //这里省略get、set方法
}

自定义ResponseParser代码如下:

@Parser(name = "Response", wrappers = {PageList.class})
public class ResponseParser<T> extends TypeParser<T> {

    //该构造方法是必须的
    protected ResponseParser() { super(); }
    //如果依赖了RxJava,该构造方法也是必须的
    public ResponseParser(Type type) { super(type); }

    @Override
    public T onParse(okhttp3.Response response) throws IOException {
        //将okhttp3.Response转换为自定义的Response对象
        Response<T> data = Converter.convertTo(response, Response.class, types);  //这里的types就是自定义Response<T>里面的泛型类型
        T t = data.getData(); //获取data字段
        if (data.getCode() != 200 || t == null) {//这里假设code不等于200,代表数据不正确,抛出异常
            throw new ParseException(String.valueOf(data.getCode()), data.getMsg(), response);
        }
        return t;
    }
}

以上代码,需要注意两个地方

第一,我们在类开头使用了@Parser注解,该注解有两个参数,如下:

  • name 代表解析器的名称,这里取名为Response,于是在RxHttp类下就会生成toObservableResponse(Class<T>)toObservableResponseList(Class<T>)方法(命名方式为:toObservable + name属性的值); 协程下会生成toAwaitResponse<T>、toFlowResponse<T>方法。

  • wrappers 该参数是可选的,可以把他理解为泛型T的包装类,需要传入Class[]数组对象,这里我们传入了{PageList.class}这个类,于是就会生成toObservableResponsePageList(Class<T>)方法。(命名方式为:toObservable +name属性的值+Class类名); 该参数协程下无效,因为对于协程,toAwaitResponse<T>()方法里面的T想写啥就可以写啥,如toAwaitResponse<List<T>>()、toAwaitResponse<PageList<T>>()

注:PageList类需要自己定义,用于加载分页数据,Demo里有这个类

第二,我们在if语句里,对code做了判断,非200或者data为空时,就抛出异常,并带上了code及msg字段,所以我们在异常回调的地方就能拿到这两个字段

此时,我们就可以通过这3个方法,直接拿到TList<T>PageList<T>类型数据,并且对code做了统一的判断,直接来看看如何使用这个解析器

//第一种方式,使用@parser注解生成的toObservableResponse方法
RxHttp.postForm("/service/...")   //发送post表单请求
    .add("key", "value")          //添加参数,可调用多次
    .toObservableResponse(Student.class)           //返回Student类型
    //.toObservableResponseList(Student.class)     //返回List<Student>类型
    //.toObservableResponsePageList(Student.class) //返回PageList<Student>类型
    .subscribe(student -> {   
        //请求成功,这里能拿到 Student对象               
    }, throwable -> {         
        //请求失败                
    });   

//kotlin环境下,也可以直接使用toObservableResponse<T>方法,更加简单如下:
RxHttp.postForm("/service/...")   //发送post表单请求
    .add("key", "value")          //添加参数,可调用多次
    .toObservableResponse<Student>()           //返回Student类型
    //.toObservableResponse<List<Student>>()     //返回List<Student>类型
    //.toObservableResponse<PageList<Student>>()  //返回PageList<Student>类型
    .subscribe({   
        //请求成功,这里能拿到 Student对象               
    }, {         
        //请求失败                
    }); 


//第二种方式,直接使用toObservable(Parser<T>)方法
RxHttp.postForm("/service/...")   //发送post表单请求
    .add("key", "value")          //添加参数,可调用多次
    .toObservable(new ResponseParser<Student>(){})    //返回Student类型
    .subscribe(student -> {   
        //请求成功,这里能拿到 Student对象               
    }, throwable -> {         
        //请求失败                
    });  

以上两种方式,除了写法上的区别,其它都一样,相信大家都会选择第一种方式,不仅写法简单,还降低了耦合。

自定义Param

自定义Param,想较于自定义Parser,要更加的简单,我们只需根据自己的需求,继承NoBodyParam、FormParam、JsonParam等,增加或者重写方法即可,比如我们有以下3种情况,需要自定义Param,如下:

  • postForm请求,需要将所有添加的参数,拼接在一起,随后加密,最后将加密的字符串添加到请求头中
  • postJson请求,需要将所有的参数,也就是json字符串加密后再发送出去
  • FormParam里面的API不够用,我要自定义API

1、postForm请求加密

这种情况,我们需要继承FormParam,并重写getRequestBody()方法,如下:

@Param(methodName = "postEncryptForm")
public class PostEncryptFormParam extends FormParam {

    public PostEncryptFormParam(String url) {
        super(url, Method.POST);  //Method.POST代表post请求
    }

    @Override
    public RequestBody getRequestBody() {
        //获取到所有通过add系列方法添加的参数
        List<KeyValuePair> bodyParam = getBodyParam();
        //获取到所有通过addQuery系列方法添加的参数
        List<KeyValuePair> queryParam = getQueryParam();
        String encryptStr = "加密后的字符串";  //根据上面拿到的参数,自行实现加密逻辑
        addHeader("encryptStr", encryptStr);
        return super.getRequestBody();
    }
}

2、postJson请求加密

这种情况,我们需要继承JsonParam,也重写getRequestBody()方法,如下:

@Param(methodName = "postEncryptJson")
public class PostEncryptJsonParam extends JsonParam {

    public PostEncryptFormParam(String url) {
        super(url, Method.POST);
    }

    @Override
    public RequestBody getRequestBody() {
        //获取到所有通过add系列方法添加的参数
        Map<String, Object> bodyParam = getBodyParam();
        //获取到所有通过addQuery系列方法添加的参数
        List<KeyValuePair> queryParam = getQueryParam();
        String encryptStr = "加密后的字符串";  //根据上面拿到的参数,自行实现解密逻辑
        return RequestBody.create(MEDIA_TYPE_JSON, encryptStr);  //发送加密后的字符串
    }
}

3、自定义API

我们继承FormParam,并新增两个test方法`,如下:

@Param(methodName = "postTestForm")
public class PostTestFormParam extends FormParam {

    public PostEncryptFormParam(String url) {
        super(url, Method.POST);
    }

    public PostEncryptFormParam test(long a, float b) {
        //这里的业务逻辑自行实现
        return this;
    }

    public PostEncryptFormParam test1(String s, double b) {
        //这里的业务逻辑自行实现
        return this;
    }
}

4、使用自定义的Param

同样的问题,我们怎么用这3个自定义的Param呢?我想大多数人在类名前发现类@Param注解,并为Param取了别名。那这个又有什么作用呢? 答案揭晓,只要在自定的Param上使用了@Param注解,并取了别名,就会在RxHttp类自动生成一个跟别名一样的方法,在上面我们自定义了3个Param,并分别取别名为postEncryptForm、postEncryptJson、postTestForm,此时就会在RxHttp类中生成postEncryptForm(String)postEncryptJsonString)postTestForm(String)这3个方法,我们在RxHttp这个类中来看下:

  public static RxHttpPostEncryptFormParam postEncryptForm(String url, Object... formatArgs) {
    return new RxHttpPostEncryptFormParam(new PostEncryptFormParam(format(url, formatArgs)));
  }

  public static RxHttpPostEncryptJsonParam postEncryptJson(String url, Object... formatArgs) {
    return new RxHttpPostEncryptJsonParam(new PostEncryptJsonParam(format(url, formatArgs)));
  }

  public static RxHttpPostTestFormParam postTestForm(String url, Object... formatArgs) {
    return new RxHttpPostTestFormParam(new PostTestFormParam(format(url, formatArgs)));
  }

发请求时,只需要调用对应的方法就好,如:

//发送加密的postForm请求
RxHttp.postEncryptForm("/service/...")   
    .add("key", "value")          //添加参数,可调用多次
    .toObservableString()         //返回Observable<String>类型
    .subscribe(s-> {   
        //请求成功    
    }, throwable -> {         
        //请求失败                
    });  

//发送加密的postJson请求
RxHttp.postEncryptJson("/service/...")   
    .add("key", "value")          //添加参数,可调用多次
    .toObservableString()         //返回Observable<String>类型
    .subscribe(s-> {   
        //请求成功    
    }, throwable -> {         
        //请求失败                
    });  

那我自定义的API如何调用呢,so easy!!!!,选择对应的请求方法后,就可以直接调用,如下:

//发送加密的postJson请求
RxHttp.postTestJson("/service/...")   
    .test(100L, 99.99F)          //调用自定义的API
    .test1("testKey", 88.88D)    //调用自定义的API
    .add("key", "value")         //添加参数,可调用多次
    .toObservableString()        //返回Observable<String>类型
    .subscribe(s-> {   
        //请求成功    
    }, throwable -> {         
        //请求失败                
    });  

自定义Converter

RxHttp内部默认使用来GsonConverter,并且额外提供了6个Converter,如下:

//非必须,根据自己需求选择 RxHttp默认内置了GsonConverter
implementation "com.github.liujingxing.rxhttp:converter-serialization:$rxhttp_version"
implementation "com.github.liujingxing.rxhttp:converter-fastjson:$rxhttp_version"
implementation "com.github.liujingxing.rxhttp:converter-jackson:$rxhttp_version"
implementation "com.github.liujingxing.rxhttp:converter-moshi:$rxhttp_version"
implementation "com.github.liujingxing.rxhttp:converter-protobuf:$rxhttp_version"
implementation "com.github.liujingxing.rxhttp:converter-simplexml:$rxhttp_version"

1、自定义TestConverter

即使这样,RxHttp也无法保证满足所有的业务需求,为此,我们可以选择自定义Converter,自定义Converter需要继承IConverter接口,如下:

public class TestConverter implements IConverter {

    /**
     * 请求成功后会被回调
     * @param body             ResponseBody
     * @param type             泛型类型
     * @param onResultDecoder  是否需要对结果进行解码/解密
     */
    @Override
    public <T> T convert(ResponseBody body, Type type, boolean onResultDecoder) throws IOException {
        //自行实现相关逻辑
        return null;
    }

    /**
     * json请求前会被回调,需要自行根据泛型T创建RequestBody对象,并返回
     */
    @Override
    public <T> RequestBody convert(T value) throws IOException {
        //自行实现相关逻辑
        return null;
    }
}

以上两个convert方法根据自身业务需求自行实现,可以参考RxHttp提供FastJsonConverter、SimpleXmlConverter等Converter

2、怎么用Converter

请查看设置Converter