当前位置: 代码迷 >> 综合 >> Retrofit+Rxjava实现嵌套逻辑的链式调用
  详细解决方案

Retrofit+Rxjava实现嵌套逻辑的链式调用

热度:96   发布时间:2023-12-15 04:27:46.0

最近做app有一个需求,service的某个接口(B接口)调用很慢,所以不能频繁的调用,然后service就想了一个逻辑:先返回一个调用速度快的接口(A接口),里面有一个字段,一旦这个字段发生了改变,再去调用第二个接口(B接口)。我们app这边的逻辑也很简单,先把A接口调用返回的值用sharedPreference存到本地,然后每次调用A接口的时候都去对比一下本地的值,要是相等就说明不需要调用B接口,要是不相等就要调用!
然后,我以最快的速度,按照之前的套路写完了
1,先写2个model类对应接口A和接口B
2,解析两个接口的数据。(Gson+okhttpfinal(封装okhttp))
3,写逻辑,先调用A,里面嵌套B
然后写完了,我突然想到,好像可以用Retrofit+Rxjava试试,因为我个人是比较反感嵌套的,尤其是波浪形到吗,剪不断理还乱的逻辑。
(友情提示:这篇文章适合已经熟悉简单的Retrofit+Rxjava模式调用接口的同学,要是不熟悉,建议先收藏本文,去熟悉一下,再回来看,你会获益匪浅。这套流程是我们国外的一个开发写的,我稍加整理,贡献给大家。)

第一步 :创建每个接口的model类

名字是
接口A的model:AppdataVersionEntity
接口B的model:AppdataDownLoadEntity
这个地方代码就不给了,很简单,如果使用gson解析json,建议使用GsonFormat插件,很方便。

第二步 :封装Retrofit

1、按照套路,创建一个类来对Retrofit进行简单的封装

 public RESTClient(Context context) {this.context = context;Retrofit retrofit = new Retrofit.Builder().baseUrl("")//这个地方一般放你的域名,所有的接口都有这种格式.client(provideOkHttpClient(context))//自定义client,如果不需要可以用默认的。                                       .addConverterFactory(GsonConverterFactory.create())//这一步就省去了手动解析json数据了。.addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build();restAPI = retrofit.create(RestAPI.class);//创建}

2、再来看上面说到的自定义client。

private OkHttpClient provideOkHttpClient(final Context context) {//抓log的,要在app的build.gradle的dependencies里面compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();File httpCacheDirectory = new File(context.getCacheDir(), "responses");//创建缓存文件Cache cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);//设置缓存10MloggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);//log的等级,4种等级,这是最详细的一种等级OkHttpClient okHttpClient = new OkHttpClient().newBuilder().connectTimeout(60 * 1000, TimeUnit.MILLISECONDS)//超时时间.readTimeout(60 * 1000, TimeUnit.MILLISECONDS)//超时时间.addInterceptor(new Interceptor() {
   //添加拦截器@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();HttpUrl httpUrl = request.url().newBuilder()//这个地方的addQueryParameter是所有接口都附加的两个值,因各家app而异,加到这个地方就省去了,在retrofit里面单独添加的麻烦。.addQueryParameter("v", "1.0.3").addQueryParameter("client","1").build();request = request.newBuilder().url(httpUrl).build();Response response = chain.proceed(request);Log.d("Response Code", response.code() + "");if (response.code() == 401) {
   //这个地方可以根据返回码做一些事情。通过sendBroadcast发出去。Intent intent = new Intent("Logout");intent.putExtra("badAuth", true);context.sendBroadcast(intent);}return response;}}).addInterceptor(loggingInterceptor)//把上面的log拦截器添加进来.cache(cache)//添加缓存.build();//build生效return okHttpClient;//返回client}

3、在这个类中,添加一个接口,来封装需要调用的接口

public interface RestAPI {
    @FormUrlEncoded@POST("接口A")Observable<AppdataVersionEntity> getAppdataVersion();@FormUrlEncoded@POST("接口B")Observable<AppdataDownLoadEntity> getAppdataDownLoad();}

然后再这个类中创建一个对外开放的方法调用接口

   private RestAPI restAPI;public RestAPI getRestAPI() {return restAPI;}

第三步:调用接口

经过上面的封装,我们可以按照逻辑,调用接口了。逻辑已经在文章的开头说过了,这里再说一遍:有一个需求,service的某个接口(B接口)调用很慢,所以不能频繁的调用,然后service就想了一个逻辑:先返回一个调用速度快的接口(A接口),里面有一个字段,一旦这个字段发生了改变,再去调用第二个接口(B接口)。我们app这边的逻辑也很简单,先把A接口调用返回的值用sharedPreference存到本地,然后每次调用A接口的时候都去对比一下本地的值,要是相等就说明不需要调用B接口,要是不相等就要调用!

 RESTClient client = new RESTClient(homeActivity);client.getRestAPI().getAppdataVersion().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<AppdataVersionEntity>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {}@Overridepublic void onNext(AppdataVersionEntity appdataVersionEntity) {
   //在调用第一个接口之后调用第二个接口,这里出现了嵌套version = appdataVersionEntity.getVersion()+"";String localVersion =  getLocalAppVersion(homeActivity);if(){
   //"本地版本发生变化"//生变化的逻辑,要去调用B接口client .getRestAPI().getAppdataDownLoad().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<AppdataDownLoadEntity>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {}@Overridepublic void onNext(AppdataDownLoadEntity appdataDownLoadEntity) {//调用了B接口,做一些逻辑}});}else{//没发生变化的逻辑}}});

上面的伪代码大体一看就行,想表达一个意思是,逻辑上要嵌套调用接口,这时候Retrofit+Rxjava也出现了嵌套,这种前台是违背了Jack设计Retrofit的初衷的,肯定是不建议的。怎么优化?用flatMap!往下看。
(要是你对observeOn和subscribeOn的关系不理解,请看我的这篇文章)

 RESTClient client = new RESTClient(homeActivity);client .getRestAPI().getAppdataVersion().flatMap(new Func1<AppdataVersionEntity, Observable<AppdataDownLoadEntity>>() {
   //调用第一个接口(A接口)**注释1**@Overridepublic Observable<AppdataDownLoadEntity> call(AppdataVersionEntity appdataVersionEntity) {if(){//如果发生了改变,就去调用接口Breturn  client.getRestAPI().getAppdataDownLoad();}else{//如果没发生改变,做一些逻辑}return null;//如果return null就继续向下执行,并不会crash}}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<AppdataDownLoadEntity>() {@Overridepublic void onNext(AppdataDownLoadEntity appdataDownLoadEntity) {//这是执行接口B,做一些逻辑}@Overridepublic void onCompleted() {JLogUtils.i("robin3","onCompleted");}@Overridepublic void onError(Throwable e) {e.printStackTrace();}});

好了,看看这代码,左边的 ## . ## 完全对其,再也不用看大波浪了,心情愉悦。最重要的是这对后面改这块代码的人很友好。

上面有一个我加粗的注释1,我想解释一下,这个地方可能会发生问题,一定要穿对泛型,否则会报错,这个泛型是什么意思呢?这要看Fun1函数的参数了,第一个是接口A的model类型(AppdataVersionEntity),第二个参数是你要去请求的B接口 ( Observable)。所以这个地方你应该也就明白了flatMap的作用:进去A,出来B。具体到项目就是,穿进去一个String,出来一个他的hashmap,传进一个userId,出来一个包含userId的model类,传一个boolean,出一个Observable。

有说的不对的,不理解的欢迎在下面指出!