ConnectableObservable
ConnectableObserable继承自Observable,具备Observable功能。
特点: (特别注意第2点)
1. ConnectableObservable数据并不是当观察者订阅时就发送数据,只
调用了connect()方法,才开始发送数据。
2. ConnectableObservable线程切换比较特别。通过"replay"操
作符实现,而且它的"订阅"和"观察"是在同相同线程。传统的
subscribeOn()和observerOn(),不起作用,如果不通过replay指
定线程,那么它的工作线程有调用线程决定。
关于线程切换,文章后面会有用法和验证
获取ConnectableObservable实例的两种方式
publish操作符
Observable通过pulish操作符获取的ConnectableObservable和PublisSubject(对PublisSubject还不熟悉的,可以看我上一篇文章Rxjava2.0中的Subject)功能基本一样,唯一区别就是,ConnectableObservable调用connect之后才开始发射数据。
ConnectableObservable<String> connect = Observable.just("1","2","3","4","5","6").publish() ;
connect.subscribe(getObserver("pob1:")) ;
connect.connect() ;
connect.subscribe(getObserver("pob2:")) ;
上述代码的执行结果,pob1会接收到123456,而pob2收不到任何数据
replay 操作符
- replay()
replay操作符生成的ConnectableObservable,无论观察者什么时候订阅,都能收到Observable发送的所有数据
ConnectableObservable<String> connect = Observable.just("1","2","3","4","5","6").replay() ;
//订阅代码省略。。。。
connect.connect(); // 开始发送数据
- replay(int buffersize)
buffersize:ConnectableObservable缓存数据源的个数,凡是在connect()之后订阅的观察者,只能收到缓存的数据,connect()之前订阅的可以收到所有数据。说白了,replay()相当于缓存了所有数据源,而replay(int buffersize)缓存指定个数的数据源。
- replay(long time, TimeUnit unit)
time:ConnectableObservable换存数据源的时间,凡是在connect之后time时间内订阅的,可接收到所有数据,time时间之后订阅的,收不到任何数据。connect()之前订阅的,可收到所有数据。- replay(Scheduler scheduler)
指定订阅和观察所在的工作线程。- replay(int buffersize, long time, TimenUnit unit)
这个方法没什么可说的,结合2、3和容易理解。- replay(int buffersize, Scheduler scheduler)
指定工作线程,并指定ConnectableObservable缓存数据源的个数。- replay(long time, Timeunit unit, Scheduler scheduler)
指定工作线程,并指定数据源缓存时间。- replay(int buffersize, long time, TimeUnit unit, Scheduler scheduler)
这个replay涵盖了以上所有的情况,我们在此用完整代码写一遍,并验证ConnectableObservable线程切换的问题。
/**
* ConnectableObservable用法和工作线程验证
* @throws InterruptedException
*/
public void rxJavaReplayConnectObservable() throws InterruptedException {
List<String> datas = Arrays.asList("A","B","C","E","F","G") ;
// 1. 缓存3个数据,保留缓存2秒钟,不指定执行线程(默认在调用线程)
ConnectableObservable<String> connect = Observable.fromIterable(datas).replay(3, 2, TimeUnit.SECONDS) ;
// 2. 指定在新开线程执行,此时如果显示Toast,会报错:子线程不能更新UI
//ConnectableObservable<String> connect = Observable.fromIterable(datas).replay(3, 2, TimeUnit.SECONDS, Schedulers.newThread()) ;
// 3. 如果使用1(即:不指定工作线程),即使在此设置订阅线程和观察线程,也不起作用
// 验证了上文所说的,ConnectableObservable只支持replay操作符指定的工作线程,下面2代码不起作用
connect.subscribeOn(Schedulers.newThread()) ;
connect.subscribeOn(AndroidSchedulers.mainThread()) ;
// connect()之前订阅,将收到所有数据:A、B、C、D、E、F、G
connect.subscribe(getObserver("Observer-1", true)) ;
// 链接,Observable开始发送数据
connect.connect() ;
// 2. 如果打开休眠3秒的方法,Observer-2,因为超过了2秒的缓存,将收不到任何数据
// Thread.sleep(3000);
// connect()之后订阅,只能收到缓存的3个数据:E、F、G
connect.subscribe(getObserver("Observer-2", false)) ;
}
private Consumer<String> getObserver(final String tag, final boolean showToast){
return new Consumer<String>() {
boolean isFirst = true ;
@Override
public void accept(@NonNull String s) throws Exception {
Log.i(TAG, tag+":>>>>>>>>>"+s) ;
if(isFirst && showToast){
Toast.makeText(mContext, tag+">>>>>>>显示成功", Toast.LENGTH_SHORT).show();
}
}
} ;
}
PS:有兴趣的话,可以复制代码自己运行验证一下(我已经验证过了,不在贴运行结果了,注释很详细,而且通过修改部分参数会有很多种执行结果)。这个最复杂的replay函数会用了,其他几个简单的不在话下。
总结
因为我有Rxjava1.0的基础,所以我是通过github上的Rxjava2的例子去学习Rxjava2的,遇到不懂地方就去官方api中学习,csdn上做记录,可能有点杂乱无章,我会慢慢整理,争取慢慢进步。