您的位置:首页 > 编程语言 > Java开发

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

2016-11-28 11:04 363 查看
最近做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);//设置缓存10M
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);//log的等级,4种等级,这是最详细的一种等级
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
.connectTimeout(60 * 1000, TimeUnit.MILLISECONDS)//超时时间
.readTimeout(60 * 1000, TimeUnit.MILLISECONDS)//超时时间
.addInterceptor(new Interceptor() {//添加拦截器
@Override
public 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>() {
@Override
public void onCompleted() {
}

@Override
public void onError(Throwable e) {
}

@Override
public 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>() {
@Override
public void onCompleted() {
}

@Override
public void onError(Throwable e) {
}

@Override
public 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**
@Override
public Observable<AppdataDownLoadEntity> call(AppdataVersionEntity appdataVersionEntity) {
if(){
//如果发生了改变,就去调用接口B
return  client.getRestAPI().getAppdataDownLoad();
}else{
//如果没发生改变,做一些逻辑
}
return null;//如果return null就继续向下执行,并不会crash
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<AppdataDownLoadEntity>() {
@Override
public void onNext(AppdataDownLoadEntity appdataDownLoadEntity) {
//这是执行接口B,做一些逻辑
}
@Override
public void onCompleted() {
JLogUtils.i("robin3","onCompleted");
}

@Override
public void onError(Throwable e) {
e.printStackTrace();
}

});


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

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

有说的不对的,不理解的欢迎在下面指出!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: