RxHttp 一条链发送请求之注解处理器 Generated API

2,994 阅读8分钟

前言

RxHttp截止 v2.2.7版本,共提供了6个注解,分别是@DefaultDomain@Domain@OkClient@Converter@Parser@Param,接下来将一一介绍。

RxHttp库已更新至2.2.7版本,详情请查看RxHttp 源码

Gradle 依赖

implementation 'com.rxjava.rxhttp:rxhttp:2.2.7'
//rxhttp v2.2.2版本起,需要手动依赖okhttp
implementation 'com.squareup.okhttp3:okhttp:4.7.2' 
//注解处理器,生成RxHttp类
annotationProcessor 'com.rxjava.rxhttp:rxhttp-compiler:2.2.7'

RxHttp 6个注解介绍

@DefaultDomain

该注解用于指定所有请求使用的默认域名,如下

public class Url {
    @DefaultDomain() //设置为默认域名
    public static String baseUrl = "https://www.wanandroid.com/";
}

此时发请求传入相对路径即可,如下:

RxHttp.get("/article/list/0/json")
    .asString()  
    .subscribe(s -> { //这里的s为String类型,即Http请求的返回结果
       //成功回调
    }, throwable -> {
       //失败回调
    });

RxHttp在发送请求前,会对url做判断,如果没有域名,就会自动加上@DefaultDomain注解指定的默认域名

@Domain

该注解用于指定非默认域名,如下:

public class Url {
    @Domain(name = "Google") //设置非默认域名,name 可不传,不传默认为变量的名称
    public static String googleUrl = "https://www.google.com";

    @DefaultDomain() //设置为默认域名
    public static String baseUrl = "https://www.wanandroid.com/";
}

此时再rebuild一下项目,就会在RxHttp类中生成一个setDomainToGoogleIfAbsent()方法,其中的Google字符就是name指定的名字,然后发请求就可以这样:

RxHttp.get("/article/list/0/json")
    .setDomainToGoogleIfAbsent()
    .add("key", "value")
    .asString()  
    .subscribe(s -> { //这里的s为String类型,即Http请求的返回结果
       //成功回调
    }, throwable -> {
       //失败回调
    });
    
//此时,完整的url为:https://www.google.com/article/list/0/json  

setDomainToGoogleIfAbsent方法内部会首先会判断我们传入的url有无域名,如果没有,就会加上我们指定的域名。

以上,可以看出,我们有3个种方式设置域名,第一种是传入的url直接带上域名;第二种使用@DefaultDomain注解指定默认的域名;第三种使用@Domain指定非默认域名,这三种优先界别如下: url带上域名 > @Domain > @DefaultDomain,其中@DefaultDomain注解优先级别最低。

注意,接下来要放大招了。。。。。

对于非默认域名,每次都要调用setDomainXxx方法才会生效,接口不多还好,多了,这种写法着实不太优雅,怎么办?

@Domain注解,其实还有一个className字段,通过指定该字段,可以生成一个RxHttp的包装类,使用该类发请求,就会默认使用@Domain注解指定的baseurl,而无需调用setDomainXxx方法,用法如下:

public class Url {
    @Domain(name = "Google",className = "Simple") 
    public static String googleUrl = "https://www.google.com";

    @DefaultDomain() //设置为默认域名
    public static String baseUrl = "https://www.wanandroid.com/";
}

此时Rebuild一下项目,就会生成一个RxSimpleHttp类,命名方法为:Rx+{className字段值}+Http,此时,我们通过RxSimpleHttp类发请求,就无需再指定非默认域名,如下:

RxSimpleHttp.get("/article/list/0/json")
    .add("key", "value")
    .asString()  
    .subscribe(s -> { //这里的s为String类型,即Http请求的返回结果
       //成功回调
    }, throwable -> {
       //失败回调
    });

//此时,完整的url为:https://www.google.com/article/list/0/json    

扩展:动态域名

也许你已经注意到了,@DefaultDomain@Domain注解修饰的常量,并没有使用final关键字,这意味着我们可直接修改这些常量,以满足动态域名的需求,如下:

//动态更改默认域名,改为立即生效
Url.baseUrl = "https://www.baidu.com/"  
RxHttp.get("/article/list/0/json")
    .asString()  
    .subscribe(s -> { //这里的s为String类型,即Http请求的返回结果
       //成功回调
    }, throwable -> {
       //失败回调
    });
    
//此时,完整的url为:https://www.baidu.com/article/list/0/json    

@OkClient

该注解,可以为某个请求指定单独的OkHttpClient对象,如下:

public class RxHttpManager {

    @OkClient(name = "BaiduClient")
    public static OkHttpClient baiduClient = new OkHttpClient.Builder().build();
}

此时Rebuild一下项目,就会在RxHttp类下生成setSimpleClient()方法,发请求时,调用该方法,就会使用@OkClient注解指定的OkHttpClient对象执行请求,如下:

RxHttp.get("/article/list/0/json")
    .setBaiduClient()
    .asString()  
    .subscribe(s -> { //这里的s为String类型,即Http请求的返回结果
       //成功回调
    }, throwable -> {
       //失败回调
    });

以上代码,将使用指定的OkHttpClient对象执行请求,如未指定,将使用默认的OkHttpClient对象。

同样的,如果请求多了,这种写法着实不优雅,此时,也许你想起了@Domain注解的className字段,没错,@OkClient注解也有该字段,如下:

public class RxHttpManager {

    @OkClient(name = "BaiduClient",className = "Baidu")
    public static OkHttpClient baiduClient = new OkHttpClient.Builder().build();
}

此时Rebuild一下项目,就是生成RxBaiduHttp类,该类将默认使用@OkClient注解指定的OkHttpClient对象执行请求,通过该类发请求就无需指定OkHttpClient对象,如下:

RxBaiduHttp.get("/article/list/0/json")
    .asString()  
    .subscribe(s -> { //这里的s为String类型,即Http请求的返回结果
       //成功回调
    }, throwable -> {
       //失败回调
    });

@Converter

该注解可以为某个请求指定单独的Converter,用于数据解析,如下:

public class RxHttpManager {

    @Converter(name = "FastJsonConverter")
    public static IConverter fastJsonConverter = FastJsonConverter.create();
}

此时Rebuild一下项目,就会在RxHttp类下生成setFastJsonConverter()方法,发请求时,调用该方法,就会使用FastJsonConverter解析数据,如下:

RxHttp.get("/article/list/0/json")
    .setFastJsonConverter()
    .asString()  
    .subscribe(s -> { //这里的s为String类型,即Http请求的返回结果
       //成功回调
    }, throwable -> {
       //失败回调
    });

到这,或许你猜到了,该注解也有className字段,如下:

public class RxHttpManager {

    @Converter(name = "FastJsonConverter",className = "FastJson")
    public static IConverter fastJsonConverter = FastJsonConverter.create();
}

此时Rebuild一下项目,就是生成RxFastJsonHttp类,通过该类发请求,就会默认使用FastJsonConverter解析数据,如下:

RxFastJsonHttp.get("/article/list/0/json")
    .asString()  
    .subscribe(s -> { //这里的s为String类型,即Http请求的返回结果
       //成功回调
    }, throwable -> {
       //失败回调
    });

Domain、OkClient、Converter注解的className字段

到这,我们知道,@Domain、@OkClient、@Converter注解,都可以指定className字段类生成对于的RxXxxHttp类,通过该类发请求,就会默认使用我们指定的域名、OkHttpClient及Converter,那么,试想一下,如果我们这三个注解,指定的className的名字都一样,会发生什么呢?如下:

public class RxHttpManager {

    @Domain(name = "Google",className = "Simple") 
    public static String googleUrl = "https://www.google.com";
    
    @OkClient(name = "BaiduClient",className = "Simple")
    public static OkHttpClient baiduClient = new OkHttpClient.Builder().build();
    
    @Converter(name = "FastJsonConverter",className = "Simple")
    public static IConverter fastJsonConverter = FastJsonConverter.create();
}

以上,className字段都取名为Simple,此时只会生成一个RxSimpleHttp类,该类默认使用的域名是googleUrl;默认的OkHttpClient对象为baiduClient;默认的Converter为FastJsonConverter,此时,使用RxSimpleHttp 发请求,如下:

RxSimpleHttp.get("/article/list/0/json")
    .asString()  
    .subscribe(s -> { //这里的s为String类型,即Http请求的返回结果
       //成功回调
    }, throwable -> {
       //失败回调
    });

//请求url:https://www.google.com/article/list/0/json 
//使用BaiduClient执行请求
//使用FastJsonConverter解析数据

注:同一类型注解,className字段取名不能一样,否则编译不通过

@Parser

先来看看源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Parser {
    //指定名字后,就会在RxHttp下生成fromXXX方法
    String name();
}

@Parser标签作用于Parser接口的实现类,指定名字后,Rebuild一下项目,就会在RxHttp下生成asXXX方法。

RxHttp 一条链发送请求之强大的数据解析功能(二)一文中,我们也自定义了一个ResponseParser解析器,同时使用了@Parser(name = "Response")注解,我们再次贴上源码

@Parser(name = "Response")
public class ResponseParser<T> extends AbstractParser<T> {
     //省略内部代码
}

然后Rebuild 一下项目,RxHttp下就会自动生产一个public <T> Observable<T> asResponse(Class<T> type)方法,如:

public class RxHttp {
  private Param param;

  private RxHttp(Param param) {
    this.param = param;
  }
  
  //通过注解Parser生成的方法
  public <T> Observable<T> asResponse(Class<T> type) {
    return asParser(new ResponseParser<T>(type));
  }
  //省略了其它方法
}

此时我们就可以直接使用asResponse方法去解析数据了。

String url = "https://www.wanandroid.com/article/list/0/json";
RxHttp.get(url) 
    .asResponse(User.class)
    ...省略部分代码

可见,代码更加的简洁了

注:@Parser注解只能作用与Parser的实现类,不能是接口和抽象类,且必须要提供两个构造方法,否则编译不通过

@Param

先来看看@Param的源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Param {
    //指定在RxHttp类中生成的静态方法名
    String methodName();
}

@Param标签只能作用于AbstractPostParam的实现类上,否则编译器会报错,指定方法名后,Rebuild一下项目,就会自动在RxHttp类下生成指定方法名的静态方法。

RxHttp 一条链发送请求之强大的Param类(三)一文中,我们自定义了一个PostEncryptJsonParam,并为它使用了注解标签@Param(methodName = "postEncryptJson")我们再次贴上该类的源码

@Param(methodName = "postEncryptJson") //指定postEncryptJson为方法名
public class PostEncryptJsonParam extends AbstractPostParam {
     //省略内部代码
}

然后Rebuild 一下项目,就可以看到在RxHttp下多了一个postEncryptJson方法,并在方法内new 出了一个PostEncryptJsonParam对象传给了RxHttp

public class RxHttp {
  private Param param;

  private RxHttp(Param param) {
    this.param = param;
  }
  
  public static RxHttp with(Param param) {
    return new RxHttp(param);
  }
  
  //通过注解Param生成的方法
  public static RxHttp postEncryptJson(String url) {
    return with(new PostEncryptJsonParam(url));
  }
  //省略了其它方法
}

接下来,我们就可以直接通过RxHttp发送PostEncryptJsonParam请求

String url = "https://www.wanandroid.com/article/list/0/json";
RxHttp.postEncryptJson(url) //这里get,代表Get请求
    .add("key", "value")    //添加参数
    //省略部分代码

可见@Param标签,在一定程度上降低了耦合,使我们并不需要关注具体的实现,使用 RxHttp类即可搞定任意请求

注:@Param标签只能作用与Param接口的实现类,该类不能是接口、抽象类,且必须提供一个public 且仅带一个url参数的构造方法,在编译时会做检查。

小结

最后,本文如果有写的不对的地方,请广大读者指出。 如果觉得我写的不错,记得给我点赞RxHttp

转载请注明出处,谢谢🙏。