Rxjava中的ConnectableObservable

本文深入讲解了ConnectableObservable的特点及用法,特别是其独特的线程切换机制和数据缓存方式。通过实例演示如何使用replay操作符来创建并管理数据流。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 操作符


  1. replay()

replay操作符生成的ConnectableObservable,无论观察者什么时候订阅,都能收到Observable发送的所有数据

ConnectableObservable<String> connect = Observable.just("1","2","3","4","5","6").replay() ;
//订阅代码省略。。。。
connect.connect();   // 开始发送数据


  1. 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上做记录,可能有点杂乱无章,我会慢慢整理,争取慢慢进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值