Android 开发 - RxRetroHttp,为多套 API 请求适配而生 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
BakerJ
V2EX    Android

Android 开发 - RxRetroHttp,为多套 API 请求适配而生

  •  
  •   BakerJ 2019-01-28 16:34:29 +08:00 11690 次点击
    这是一个创建于 2452 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

    "后端新换代,新接口返回全用新的规则,老接口不变!"。。。WTF !

    “我们的这几个网站,要做一个统一的 App,后端都是现成的,这是 API 文档。”。。。几个网站的 API 规范和请求 Host 地址居然完全不一样?。。。WTF !

    。。。千万只草泥马呼啸而过。。。实时切换 BaseUrl ? Retrofit 注解全加上 @Url ?。。。无奈。。。

    虽然说现在已经有很多 Http 请求框架了,也有很多针对 RxJava+Retrofit 的二次封装,其中也不乏很多动态替换 BaseUrl 的框架。但是如果需要更好的处理除了 BaseUrl 之外需求,比如针对各套 API 规则,不同的拦截处理、不同的返回异常逻辑处理等等,大多没有给予解决方案。因此,RxRetroHttp 应运而生。

    Github 地址: https://github.com/BakerJQ/RxRetroHttp

    总览

    我们先来看看,RxRetroHttp 是通过什么方式处理这种情况的。

    初始化

    首先,大多库的必备阶段:初始化。我们先来看看初始化的代码,在 Application 的 onCreate 中执行

    RxRetroHttp.init(this) .setBaseUrl("http://api1.com/") .setApiResultClass(Api1Result.class) .generateRetroClient() 

    这样,初始化就做完了。。。此处应有掌声。。。

    “我掌你大爷!!!说好的处理多套 API 规则呢!!!”

    额咳。。。客观莫急。。。待我徐徐道来

    通过刚刚的初始化,你已经设置了 App 中主 API 请求的基本配置。如果你的 App 中,就像前言里描述的那样,需要对接多套 API 规则,那么在初始化之后,再加入如下代码

    RxRetroHttp.getInstance() .setBaseUrl("https://api2.com/") .setApiResultClass(Api2Result.class) .generateRetroClient("API2") 

    相信大家已经看出区别了吧,没错,就是在 generateRetroClient 这个方法中,加入了一个 Tag,而这个 Tag,就是处理多套 API 请求的关键。

    在 setApiResultClass 方法中,传入的就是对于 API 规范的基类,具体情况会在后面讲到。

    调用

    初始化完成后,如何调用呢

    RxRetroHttp.create(Api2Service.class).getApi2Info() 

    我们可以看到,这就是 Retrofit 风格的调用方式。

    在这里,Api2Service 也就是 Retrofit 风格的 ApiService,但是也略有不同

    @RetroTag("API2") public interface Api2Service { @GET("test/info") Observable<Api2Info> getApi2Info(); } 

    我们看看不同在哪,下面是纯 Retrofit 的书写方式

    public interface Api2Service { @GET("test/info") Observable<Api2Result<Api2Info>> getApi2Info(); } 

    没错,区别就在于:

    1、省去了基类的这一层包裹。这么做的原因是,个人认为,在 ApiService 这一层,每个接口定义都需要设置 ApiResult 包裹是不人性的,哈哈哈。

    2、RetroTag 接口,用于指示 Tag,当然这是对于初始化时设置了 Tag 的 API 请求。

    当然,如果你还是希望以基类包裹的方式,也是可以的,那就是在初始化的时候,不调用 setApiResultClass 方法就行了。

    另外,如果你不想增加 RetroTag 注解,也是可以的,那在调用的时候,就需要调用另一个方法,放入 Tag,如下:

    RxRetroHttp.create(Api2Service.class, "API2").getApi2Info() 

    ApiResult

    现在,我们来看看 ApiResult。

    在 setApiResultClass 方法中传入的,是实现了 IApiResult 接口的请求返回基类,简单的样例代码如下

    public class Api2Result<T> implements IApiResult<T> { private int code; private String msg; private T result; @Override public boolean isSuccess(){ return code == 1; } @Override public T getData(){ return result; } @Override public String getResultMsg(){ return msg; } @Override public String getResultCode(){ return String.valueOf(code); } @Override public String getDataField(){ return "result"; } } 

    其对应的返回 json 如下

    { code: 1, msg: "请求成功", result: { ... } } 

    这是一个较为常用的 API 返回格式,而我们所要做的,就是实现几个基本方法,其中,isSuccess()返回的是请求成功的判断,getData()返回的是请求到的具体数据,getResultMsg()返回的是 API 请求信息,getResultCode()表示返回码,getDataField()返回的是 json 数据中表示具体数据的字段(在上面的 json 例子中,就是“ result ”)。

    更多配置

    Http 请求不可能没有相关的配置,而本框架并没有为大家内置很多配置方法,原因是,我认为这并不是本框架的主要功能。当然,大家也是可以进行自定义配置的,配置方式如下:

    RxRetroHttp.init(this).setXXX().setXXX(); Retrofit.Builder retrofitBuilder = RxRetroHttp.getRetrofitBuilder(); retrofitBuilder.setXXX().setXXX(); OkHttpClient.Builder okHttpBuilder = RxRetroHttp.getOkHttpClientBuilder(); okHttpBuilder.setXXX().setXXX(); RxRetroHttp.getInstance().generateRetroClient(); //RxRetroHttp.getInstance().generateRetroClient("YourTag") 

    当然各套 API 请求之间的配置也是隔离的。框架也提供了一些简单的快捷配置方法,比如 addInterceptor、addNetworkInterceptor 等,更多的配置可以通过上述方式,获取 retrofitBuilder 和 okHttpBuilder 来配置。

    总结

    通过 Tag 的方式或许不是最好的方式,我也会继续尝试其他的方式,以对比便利性,如果大家有更好的方案提议,也希望能够通过提 issuer 的方式告诉我,感谢大家。

    更具体的使用方式,欢迎来 GitHub 仓库里的 Demo 查看,也欢迎和感谢各位 Star 支持。

    再次贴一下 Github 地址: https://github.com/BakerJQ/RxRetroHttp

    9 条回复    2019-01-29 18:59:13 +08:00
    kile
        1
    kile  
       2019-01-28 17:22:22 +08:00
    retrofit 在这种情况下违背了作者的思想...所以弄的很纠结...

    我的建议就是项目中有可能多 BaseUrl 的话,就别上 retrofit 了...

    这在非 retrofit 的网络请求工具中,无非就是拼个地址的事...
    theshyyyyy
        2
    theshyyyyy  
       2019-01-28 17:44:06 +08:00
    感觉使用场景有点罕见
    jellyEmmm
        3
    jellyEmmm  
       2019-01-29 10:40:38 +08:00
    https://github.com/JessYanCoding/RetrofitUrlManager

    了解一下,你这个代码侵入性太强了
    seselin
        4
    seselin  
       2019-01-29 11:26:19 +08:00
    求教,上面那张图片使用什么工具做的?
    BakerJ
        5
    BakerJ  
    OP
       2019-01-29 14:05:16 +08:00
    @jellyEmmm 那个我很早就看过了,他的只能够单纯的替换 url,通过 Intercepter+注解的方式。但是我所解决的问题是,除了 BaseUrl 之外,多套规则下返回解析、拦截处理、header、异常处理等机制都不同的情况。这样的话,即使用你发的这个,我也要在业务代码里,去指定返回结果等等很多其他的东西
    BakerJ
        6
    BakerJ  
    OP
       2019-01-29 14:06:05 +08:00
    @theshyyyyy 是非常特殊,但就是被我碰到了。。。。。。。无奈。。。。
    BakerJ
        7
    BakerJ  
    OP
       2019-01-29 14:06:52 +08:00
    @kile 不单单是 Url,而是解析规则、异常处理等很多都有多套
    BakerJ
        8
    BakerJ  
    OP
       2019-01-29 14:07:11 +08:00
    @seselin PS 呗
    twoyuan
        9
    twoyuan  
       2019-01-29 18:59:13 +08:00
    不知道是不是我没看懂楼主的需求……

    多个 Base URL 不是直接创建对应多个 Api 的 Service 吗,然后每个服务端的约定对应不同的拦截器就好了。如果 Base URL 也是通过接口获取的话,就在获取之后再创建这个 Api 的 Service 实例
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1065 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 18:10 PVG 02:10 LAX 11:10 JFK 14:10
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86