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模式调用接口的同学,要是不熟悉,建议先收藏本文,去熟悉一下,再回来看,你会获益匪浅。这套流程是我们国外的一个开发写的,我稍加整理,贡献给大家。)
接口A的model:AppdataVersionEntity
接口B的model:AppdataDownLoadEntity
这个地方代码就不给了,很简单,如果使用gson解析json,建议使用GsonFormat插件,很方便。
2、再来看上面说到的自定义client。
3、在这个类中,添加一个接口,来封装需要调用的接口
然后再这个类中创建一个对外开放的方法调用接口
上面的伪代码大体一看就行,想表达一个意思是,逻辑上要嵌套调用接口,这时候Retrofit+Rxjava也出现了嵌套,这种前台是违背了Jack设计Retrofit的初衷的,肯定是不建议的。怎么优化?用flatMap!往下看。
(要是你对observeOn和subscribeOn的关系不理解,请看我的这篇文章)
好了,看看这代码,左边的 ## . ## 完全对其,再也不用看大波浪了,心情愉悦。最重要的是这对后面改这块代码的人很友好。
上面有一个我加粗的注释1,我想解释一下,这个地方可能会发生问题,一定要穿对泛型,否则会报错,这个泛型是什么意思呢?这要看Fun1函数的参数了,第一个是接口A的model类型(AppdataVersionEntity),第二个参数是你要去请求的B接口 ( Observable)。所以这个地方你应该也就明白了flatMap的作用:进去A,出来B。具体到项目就是,穿进去一个String,出来一个他的hashmap,传进一个userId,出来一个包含userId的model类,传一个boolean,出一个Observable。
有说的不对的,不理解的欢迎在下面指出!
然后,我以最快的速度,按照之前的套路写完了
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。
有说的不对的,不理解的欢迎在下面指出!
相关文章推荐
- RxJava(十一)defer操作符实现代码支持链式调用
- RxJava(十一)defer操作符实现代码支持链式调用
- RxJava(十一)defer操作符实现代码支持链式调用
- (4.6.22.1)来吧,是时候撸一份自己的RxJava框架啦:观察者模式实现链式调用
- 更新上篇文章 调用三级目录文章内容 dede频道页实现三级栏目嵌套调用文章
- jetty之HandlerWrapper与链式调用的实现
- 编程技巧:使用LINQ如何通过多次调用GroupBy实现分组嵌套
- javascript实现简单的链式调用
- JavaScript中两种链式调用实现代码
- JavaScript实现链式调用
- dede频道页实现三级栏目嵌套调用文章
- Javascript 链式调用实现代码(参考jquery)
- 第51讲:Scala中链式调用风格的实现代码实战及其在Spark编程中的广泛运用学习笔记
- 飘逸的python - 实现链式调用
- html嵌套iframe如何实现等iframe页面加载完进行下一步调用
- javascript链式调用实现方式总结
- 如何在PHP中实现链式方法调用
- Javascript 链式调用实现代码(参考jquery)
- javascript链式调用的实现方式
- Jetty之HandlerWrapper与链式调用的实现