Rxjava的使用篇二

一、背景
此前针对Rxjava的使用进行了学习,编写了Rxjava的介绍和使用篇一( https://blog.csdn.net/polo2044/article/details/79561415),但是在实际项目中还存在其它使用方法没有接触过,下面将结合使用场景对它们进行介绍。
二、Rxjava的使用介绍
2.1 zip方法
场景描述:比如APP应用在启动初始化的过程中,会去检测版本更新和用户所关注的信息是否有更新,在设计上会使用Retrofit网络框架分别对版本更新的情况和用户关注信息的更新情况同后台进行网络交互。但是现在产品提出了新的需求,如果存在版本更新的情况下,不在向用户提示他所关注的信息有更新。
场景中存在的设计难点:由于检测版本更新和检测用户关注信息更新是两个不同的请求,因此在代码中需要判断两个不同的请求是否都结束,在综合两份返回信息合并到一起进行判断之后才能满足新需求。
如果自己动手写针对两次网络请求都结束的判断逻辑,虽然不算复杂,但是还是会花上一点功夫。Rxjava就恰巧提供了这样的API,根据Rxjava zip的API介绍,zip会将多个被观察者的结果合并成一个Fun*,然后用一个被观察者发送出去。
参考如下代码:
//检测收藏更新
Observable<CollectUpdateList> checkCollectionUpdater = MkzRetrofit.getInstance( this )
.checkCollectUpdateList(userName, userSecret)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
//检测版本更新
final int versionCode = BaseConfig.versionCode;
Observable<AppUpdateInfo> checkUpdater = MkzRetrofit.getInstance( this )
.checkAppUpdate(versionCode)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
//使用zip将收藏更新和版本更新两份请求合并到一起
Observable.zip(collectionUpdater, checkUpdater, new Func2<CollectUpdateList, AppUpdateInfo, Pair<CollectUpdateList, AppUpdateInfo>>() {
//通过定义一个Pair对象将收藏更新对象collectUpdateList和应用版本更新对象凑成一个对象返回
@Override
public Pair<CollectUpdateList, AppUpdateInfo> call (CollectUpdateList collectUpdateList, AppUpdateInfo appUpdateInfo) {
return new Pair<CollectUpdateList, AppUpdateInfo>(collectUpdateList, appUpdateInfo);
}
}).subscribe( new Action1<Pair<CollectUpdateList, AppUpdateInfo>>() {
@Override
public void call (Pair<CollectUpdateList, AppUpdateInfo> result) {
isShowingUpdateDialog = false ;
if (result.second.isSuccess()) {
boolean hasUpdate = checkUpdateInfo(versionCode, result.second);
if (!hasUpdate) {
autoStartCache();
}
}
//在没有更新对话框的情况下考虑显示收藏更新对话框
if (!isShowingUpdateDialog) {
if ((result.first.getCount() > 0 ) && !result.first.getList().isEmpty()) {
showCollectUpdate(result.first);
}
}

}
},
new Action1<Throwable>() {
@Override
public void call (Throwable throwable) {

}
}
);
在上述代码中可分为如下四步:1.使用retrofit+Rxjava定义一个收藏更新的Observable;2使用retrofit+Rxjava定义一个版本更新的Observable;3.使用Rxjava的zip将收藏更新的Observable和版本更新的Observable合并成一个Observable;4.在zip合并的Observable中使用fun和Pair,将收藏更新和版本更新的结果合并成一个对象的结果。后续的观察者代码根据返回的合并的结果进行逻辑判断,设计在有版本更新的情况下,不显示收藏更新。
2.2 Rxjava的背压
场景描述:在APP的设计中,经常会碰到这样的场景,在一个服务中进行下载任务,在Activity组件中显示下载的进度。通过Rxjava实现这一场景不算难事,将服务中的下载任务设计成一个Observable(被观察者),在Activity中定义一个Observer订阅Observable的下载进度。但是现在存在一个,就是下载任务给出的进度值过于频繁,这将导致Activity中的订阅者不能及时处理下载的进度值。
解决方案:这种情况下需要使用Rxjava背压方式来调节被观察者和观察者之间发送事件和处理事件的速度。
参考代码如下:
//下载服务端的代码
public class DownloadService extends Service {
private static final PublishSubject < DownloadInfo > DOWNLOAD_SUBJECT = PublishSubject .create();
public static Observable < DownloadInfo > getStatusObservable() {
return DOWNLOAD_SUBJECT .onBackpressureLatest();
}
private class DownLoadThread extends Thread {
@Override
public void run() {
//进行下载任务
}
private void updateStatus( DownloadInfo downloadInfo) {
DOWNLOAD_SUBJECT .onNext(chapterInfo);
}
}
}
关于Rxjava背压的介绍,可参考链接 https://www.jianshu.com/p/a75ecf461e02
2.3 Rxjava compose和transform
场景描述:第一次见到Rxjava的compose和transform的使用,是Rxjava应用在Activity和Fragment的Retorfit网络请求的过程中,在Activity和Fragment的基类中会使用transform定义一个函数,用于判断页面是否会退出,在使用的Activity和Fragment子类的retrofit网络请求中,会使用compose来中途判断一下页面是否有退出。由于见到的代码比较复杂,不利于此处分析,下面将从另一个例子来分析使用。
参见zip方法中的示例代码,在进行网络请求时一般会将网络请求的代码放置在IO线程中进行操作,界面显示部分放置在UI线程中进行:
Observable<CollectUpdateList> checkCollectionUpdater = MkzRetrofit.getInstance( this )
.checkCollectUpdateList(userName, userSecret)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) ;
如果计划将这个线程切换操作制作成一个函数供代码中所有有类似操作的部分进行调用,事先不考虑使用compose和transform。可能我们会编写如下函数
<T> Observable<T> applySchedulers(Observable<T> observable) {
return observable .subscribeOn (Schedulers .io ())
.observeOn (AndroidSchedulers .mainThread ()) ;
}
然后将 MkzRetrofit.getInstance( this ).checkCollectUpdateList(userName, userSecret)作为参数传递入该函数获取返回值。
使用compose和transform
transform继承于fun1,从源码的介绍上可知,transform所做的工作是将原有的Observable转换成另一个Observable输出。
/**
* Function that receives the current Observable and should return another
* Observable, possibly with given element type, in exchange that will be
* subscribed to by the downstream operators and subscribers.
* <p>
* This convenience interface has been introduced to work around the variance declaration
* problems of type arguments.
*
* @param <T> the input Observable's value type
* @param <R> the output Observable's value type
*/
public interface Transformer< T , R > extends Func1<Observable< T >, Observable< R >> {
// cover for generics insanity
}
compose 可以理解为用来提供transform转化的Observable的输出。
将上述的函数使用compose和transform进行改造可得如下函数
< T > Transformer< T , T > applySchedulers() {
return observable -> observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
调用方式如下:
Observable <CollectUpdateList> checkCollectionUpdater = MkzRetrofit.getInstance(this)
.checkCollectUpdateList( user Name, user Secret)
.compose(applySchedulers());
如果希望控制compose的返回类型为Type可以进行如下定义:
Observable.from(someSource)
. map ( data -> manipulate( data ))
.compose(this.< Type >applySchedulers())
. subscribe ( data -> doSomething( data ));
compose,transform和函数的比较,相比函数调用方式保护了Rxjava的流式调用,并且能够很方便的指定返回的类型。另外从网络上可以了解到compose的如下优点:
  • compose()是唯一一个能够从数据流中得到原始Observable的操作符,所以,那些需要对整个数据流产生作用的操作(比如,subscribeOn()和observeOn())需要使用compose()来实现。相较而言,如果在flatMap()中使用subscribeOn()或者observeOn(),那么它仅仅对在flatMap()中创建的Observable起作用,而不会对剩下的流产生影响(译者注:深坑,会在后面的系列着重讲解,欢迎关注)。
  • 当创建Observable流的时候,compose()会立即执行,犹如已经提前写好了一个操作符一样,而flatMap()则是在onNext()被调用后执行,onNext()的每一次调用都会触发flatMap(),也就是说,flatMap()转换每一个事件,而compose()转换的是整个数据流。
  • 因为每一次调用onNext()后,都不得不新建一个Observable,所以flatMap()的效率较低。事实上,compose()操作符只在主干数据流上执行操作。

猜你喜欢

转载自blog.csdn.net/polo2044/article/details/79903086