RxJava操作符(四)Combining

文章介绍了RxJava中用于组装多个Observable数据的四种操作符:CombineLatest、Join、Merge、StartWith。详细解释了各操作符的工作原理、参数及应用实例,并通过代码示例展示了如何使用这些操作符进行数据组合。

RxJava操作符(四)Combining

原文链接 http://blog.chinaunix.net/uid-20771867-id-5197584.html


 上一篇文章中我们了解了如何对数据进行过滤,在这篇文章里我们来了解一下如何组装多个Observable的数据。

    一、CombineLatest
    CombineLatest操作符可以将2~9个Observable发射的数据组装起来然后再发射出来。不过还有两个前提:
    1.所有的Observable都发射过数据。
    2.满足条件1的时候任何一个Observable发射一个数据,就将所有Observable最新发射的数据按照提供的函数组装起来发射出去。
    
    Rxjava实现CombineLast操作符可以让我们直接将组装的Observable作为参数传值,也可以将所有的Observable装在一个List里面穿进去。

    下面我们创建几个Observable对象,分别直接传值和使用List传值将其组装起来

点击(此处)折叠或打开

  1. private Observable<Integer> createObserver(int index) {
  2.         return Observable.create(new Observable.OnSubscribe<Integer>() {
  3.             @Override
  4.             public void call(Subscriber<? super Integer> subscriber) {
  5.                 for (int i = 1; i < 6; i++) {
  6.                     subscriber.onNext(* index);
  7.                     try {
  8.                         Thread.sleep(1000);
  9.                     } catch (InterruptedException e) {
  10.                         e.printStackTrace();
  11.                     }
  12.                 }
  13.             }
  14.         }).subscribeOn(Schedulers.newThread());
  15.     }

  16.     private Observable<Integer> combineLatestObserver() {
  17.         return Observable.combineLatest(createObserver(1), createObserver(2), (num1, num2) -> {
  18.             log("left:" + num1 + " right:" + num2);
  19.             return num1 + num2;
  20.         });
  21.     }

  22.     List<Observable<Integer>> list = new ArrayList<>();

  23.     private Observable<Integer> combineListObserver() {
  24.         for (int i = 1; i < 5; i++) {
  25.             list.add(createObserver(i));
  26.         }
  27.         return Observable.combineLatest(list, args -> {
  28.             int temp = 0;
  29.             for (Object i : args) {
  30.                 log(i);
  31.                 temp += (Integer) i;
  32.             }
  33.             return temp;
  34.         });
  35.     }
    对其进行订阅

点击(此处)折叠或打开

  1. mLButton.setText("combineList");
  2.         mLButton.setOnClickListener(-> combineListObserver().subscribe(-> log("combineList:" + i)));
  3.         mRButton.setText("CombineLatest");
  4.         mRButton.setOnClickListener(-> combineLatestObserver().subscribe(-> log("CombineLatest:" + i)));
    运行结果如下


     二、Join
    Join操作符根据时间窗口来组合两个Observable发射的数据,每个Observable都有一个自己的时间窗口,要组合的时候,在这个时间窗口内的数据都有有效的,可以拿来组合。
    Rxjava还实现了groupJoin,基本和join相同,只是最后组合函数的参数不同。

    使用join操作符需要4个参数,分别是:
    1.源Observable所要组合的目标Observable
    2.一个函数,就收从源Observable发射来的数据,并返回一个Observable,这个Observable的生命周期决定了源Observable发射出来数据的有效期
    3. 一个函数,就收从目标Observable发射来的数据,并返回一个Observable,这个Observable的生命周期决定了目标Observable发射出来数据的有效期
    4.一个函数,接收从源Observable和目标Observable发射来的数据,并返回最终组合完的数据。
      
    下面我们使用join和groupJoin操作符分别来组合两个Observable对象

点击(此处)折叠或打开

  1. private Observable<String> createObserver() {
  2.         return Observable.create(new Observable.OnSubscribe<String>() {
  3.             @Override
  4.             public void call(Subscriber<? super String> subscriber) {
  5.                 for (int i = 1; i < 5; i++) {
  6.                     subscriber.onNext("Right-" + i);
  7.                     try {
  8.                         Thread.sleep(1000);
  9.                     } catch (InterruptedException e) {
  10.                         e.printStackTrace();
  11.                     }
  12.                 }
  13.             }
  14.         }).subscribeOn(Schedulers.newThread());
  15.     }


  16.     private Observable<String> joinObserver() {
  17.         return Observable.just("Left-").join(createObserver(),
  18.                 integer -> Observable.timer(3000, TimeUnit.MILLISECONDS),
  19.                 integer -> Observable.timer(2000, TimeUnit.MILLISECONDS),
  20.                 (i, j) -> i + j
  21.         );
  22.     }

  23.     private Observable<Observable<String>> groupJoinObserver() {
  24.         return Observable.just("Left-")
  25.                 .groupJoin(createObserver(),
  26.                         s -> Observable.timer(3000, TimeUnit.MILLISECONDS),
  27.                         s -> Observable.timer(2000, TimeUnit.MILLISECONDS),
  28.                         (s, stringObservable) -> stringObservable.map(str -> s + str));
  29.     }
    分别进行订阅

点击(此处)折叠或打开

  1. mLButton.setText("join");
  2. mLButton.setOnClickListener(-> joinObserver().subscribe(-> log("join:" + i + "\n")));
  3. mRButton.setText("groupJoin");
  4. mRButton.setOnClickListener(-> groupJoinObserver().subscribe(-> i.subscribe(-> log("groupJoin:" + j + "\n"))));
    运行结果如下,可以看到虽然目标Observable发射了4个数据,但是源Observable只发射了一个有效期为3秒的数据,所以最终的组合结果也只有3个数据。


     三、Merege
    Merge操作符将多个Observable发射的数据整合起来发射,就如同是一个Observable发射的数据一样。但是其发射的数据有可能是交错的,如果想要没有交错,可以使用concat操作符。
    当某一个Observable发出onError的时候,merge的过程会被停止并将错误分发给Subscriber,如果不想让错误终止merge的过程,可以使用MeregeDelayError操作符,会将错误在merge结束后再分发。

    下面我们分别使用merge和mergeDelayError操作符来进行merge操作。

点击(此处)折叠或打开

  1. private Observable<Integer> mergeObserver() {
  2.         return Observable.merge(Observable.just(1, 2, 3), Observable.just(4, 5, 6));
  3.     }

  4.     private Observable<Integer> mergeDelayErrorObserver() {
  5.         return Observable.mergeDelayError(Observable.create(new Observable.OnSubscribe<Integer>() {
  6.             @Override
  7.             public void call(Subscriber<? super Integer> subscriber) {
  8.                 for (int i = 0; i < 5; i++) {
  9.                     if (== 3) {
  10.                         subscriber.onError(new Throwable("error"));
  11.                     }
  12.                     subscriber.onNext(i);

  13.                 }
  14.             }
  15.         }), Observable.create(new Observable.OnSubscribe<Integer>() {
  16.             @Override
  17.             public void call(Subscriber<? super Integer> subscriber) {
  18.                 for (int i = 0; i < 5; i++) {
  19.                     subscriber.onNext(+ i);
  20.                 }
  21.                 subscriber.onCompleted();
  22.             }
  23.         }));
  24.     }
    分别对其订阅
    

点击(此处)折叠或打开

  1. mLButton.setText("Merge");
  2.         mLButton.setOnClickListener(-> mergeObserver().subscribe(-> log("Merge:" + i)));
  3.         mRButton.setText("mergeDelayError");
  4.         mRButton.setOnClickListener(-> mergeDelayErrorObserver().subscribe(new Subscriber<Integer>() {
  5.             @Override
  6.             public void onCompleted() {
  7.                 log("onCompleted");
  8.             }

  9.             @Override
  10.             public void onError(Throwable e) {
  11.                 log("mergeDelayError:" + e);

  12.             }

  13.             @Override
  14.             public void onNext(Integer integer) {
  15.                 log("mergeDelayError:" + integer);

  16.             }
  17.         }));
    运行结果如下。


     四、StartWith、Switch
    StartWith操作符会在源Observable发射的数据前面插上一些数据。不仅仅只可以插入一些数据,还可以将Iterable和Observable插入进入。如果插入的是Observable,则这个Observable发射的数据会插入到
源Observable发射数据的前面。

    switch操作符在Rxjava上的实现为switchOnNext,用来将一个发射多个小Observable的源Observable转化为一个Observable,然后发射这多个小Observable所发射的数据。
需要注意的就是,如果一个小的Observable正在发射数据的时候,源Observable又发射出一个新的小Observable,则前一个Observable发射的数据会被抛弃,直接发射新
的小Observable所发射的数据。可以看示意图中的黄色圆圈就被丢弃了。


    下面使用startWith和switchOnNext操作符来组合两个Observable

点击(此处)折叠或打开

  1. private Observable<Integer> startWithObserver() {
  2.         return Observable.just(1, 2, 3).startWith(-1, 0);
  3.     }

  4.     private Observable<String> switchObserver() {
  5.         return Observable.switchOnNext(Observable.create(
  6.                 new Observable.OnSubscribe<Observable<String>>() {
  7.                     @Override
  8.                     public void call(Subscriber<? super Observable<String>> subscriber) {
  9.                         for (int i = 1; i < 3; i++) {
  10.                             subscriber.onNext(createObserver(i));
  11.                             try {
  12.                                 Thread.sleep(2000);
  13.                             } catch (InterruptedException e) {
  14.                                 e.printStackTrace();
  15.                             }
  16.                         }
  17.                     }
  18.                 }
  19.         ));
  20.     }

  21.     private Observable<String> createObserver(int index) {
  22.         return Observable.create(new Observable.OnSubscribe<String>() {
  23.             @Override
  24.             public void call(Subscriber<? super String> subscriber) {
  25.                 for (int i = 1; i < 5; i++) {
  26.                     subscriber.onNext(index + "-" + i);
  27.                     try {
  28.                         Thread.sleep(1000);
  29.                     } catch (InterruptedException e) {
  30.                         e.printStackTrace();
  31.                     }
  32.                 }
  33.             }
  34.         }).subscribeOn(Schedulers.newThread());
  35.     }
    分别进行订阅

点击(此处)折叠或打开

  1. mLButton.setText("StartWith");
  2. mLButton.setOnClickListener(-> startWithObserver().subscribe(-> log("StartWith:" + i)));
  3. mRButton.setText("switch");
  4. mRButton.setOnClickListener(-> switchObserver().subscribe(-> log("switch:" + i)));
    运行结果如下,可以看到startwith将-1和0插入到前面。使用siwtch的时候第一个小Observable只发射出了两个数据,第二个小Observable就被源Observable发射出来了,所以其接下来的两个数据被丢弃。


     五、Zip
    Zip操作符将多个Observable发射的数据按顺序组合起来,每个数据只能组合一次,而且都是有序的。最终组合的数据的数量由发射数据最少的Observable来决定。
    Rxjava实现了zip和zipWith两个操作符。

    下面我们使用zip和zipWith操作符来组合数据
    

点击(此处)折叠或打开

  1. private Observable<String> zipWithObserver() {
  2.         return createObserver(2).zipWith(createObserver(3), (s, s2) -> s + "-" + s2);
  3.     }

  4.     private Observable<String> zipWithIterableObserver() {
  5.         return Observable.zip(createObserver(2), createObserver(3), createObserver(4), (s, s2, s3) -> s + "-" + s2 + "-" + s3);
  6.     }

  7.     private Observable<String> createObserver(int index) {
  8.         return Observable.create(new Observable.OnSubscribe<String>() {
  9.             @Override
  10.             public void call(Subscriber<? super String> subscriber) {
  11.                 for (int i = 1; i <= index; i++) {
  12.                     log("emitted:" + index + "-" + i);
  13.                     subscriber.onNext(index + "-" + i);
  14.                     try {
  15.                         Thread.sleep(500);
  16.                     } catch (InterruptedException e) {
  17.                         e.printStackTrace();
  18.                     }
  19.                 }
  20.             }
  21.         }).subscribeOn(Schedulers.newThread());
  22.     }
    分别进行订阅

点击(此处)折叠或打开

  1. mLButton.setText("zipWith");
  2. mLButton.setOnClickListener(-> zipWithObserver().subscribe(-> log("zipWith:" + i + "\n")));
  3. mRButton.setText("zip");
  4. mRButton.setOnClickListener(-> zipWithIterableObserver().subscribe(-> log("zip:" + i + "\n")));
    运行结果如下,可以看到,最终都发射出了两个数据,因为createObserver(2)所创建的Observable只会发射两个数据,所以其他Observable多余发射的数据都被丢弃了。
  

    Combning的操作符就到这了,本文中的源码见 https://github.com/Chaoba/RxJavaDemo  

Combine框架是苹果公司推出的一个用于处理异步事件流的声明式框架,广泛应用于iOS、macOS及其他苹果平台的开发中。它提供了一种统一的方式来处理异步事件,如用户输入、网络请求和定时器等。在Combine中,操作符(Operators)是用于转换、过滤和组合事件流的关键工具。以下是一些常见的操作符及其用途: ### 转换操作符(Transformation Operators) 这些操作符用于修改发布者(Publisher)发出的值。 - **`map`**:将每个发出的值通过一个函数进行转换。例如,可以将一个整数流转换为字符串流。 ```swift let publisher = [1, 2, 3].publisher publisher.map { "Number: \($0)" } .sink { print($0) } ``` - **`flatMap`**:用于将每个发出的值映射为一个新的发布者,并将这些发布者的输出合并到一个新的发布者中。常用于处理嵌套的异步操作。 ```swift let publisher = [1, 2, 3].publisher publisher.flatMap { number in Future<String, Never> { promise in DispatchQueue.global().async { promise(.success("Number: $number)")) } } } .sink { print($0) } ``` - **`replaceNil`**:将流中的`nil`值替换为指定的默认值。 ```swift let publisher = [1, nil, 3].publisher publisher.replaceNil(with: 0) .sink { print($0) } ``` ### 过滤操作符(Filtering Operators) 这些操作符用于筛选发布者发出的值。 - **`filter`**:根据提供的条件筛选出符合条件的值。 ```swift let publisher = [1, 2, 3, 4, 5].publisher publisher.filter { $0 % 2 == 0 } .sink { print($0) } ``` - **`prefix`**:只取前N个发出的值。 ```swift let publisher = [1, 2, 3, 4, 5].publisher publisher.prefix(3) .sink { print($0) } ``` - **`distinctUntilChanged`**:仅当当前值与上一个值不同时才发出。 ```swift let publisher = [1, 1, 2, 2, 3].publisher publisher.distinctUntilChanged() .sink { print($0) } ``` ### 组合操作符Combining Operators) 这些操作符用于组合多个发布者的输出。 - **`merge`**:将多个发布者的输出合并到一个流中。 ```swift let publisher1 = [1, 2].publisher let publisher2 = [3, 4].publisher publisher1.merge(with: publisher2) .sink { print($0) } ``` - **`zip`**:将多个发布者的输出按顺序配对并发出。 ```swift let publisher1 = [1, 2].publisher let publisher2 = ["A", "B"].publisher publisher1.zip(publisher2) .sink { print("Number: $0.0), Letter: $0.1)") } ``` - **`combineLatest`**:当任一发布者发出新值时,输出所有发布者的最新值。 ```swift let publisher1 = PassthroughSubject<Int, Never>() let publisher2 = PassthroughSubject<String, Never>() publisher1.combineLatest(publisher2) .sink { print("Number: $0.0), Letter: $0.1)") } publisher1.send(1) publisher2.send("A") publisher1.send(2) publisher2.send("B") ``` ### 错误处理操作符(Error Handling Operators) 这些操作符用于处理发布者可能发出的错误。 - **`catch`**:捕获发布者发出的错误,并提供一个替代的发布者继续执行。 ```swift let publisher = Future<Int, Error> { promise in promise(.failure(NSError(domain: "", code: -1, userInfo: nil))) } publisher.catch { _ in Just(0) } .sink(receiveCompletion: { _ in }, receiveValue: { print($0) }) ``` - **`retry`**:在发生错误时重新订阅发布者。 ```swift var count = 0 let publisher = Future<Int, Error> { promise in if count < 2 { count += 1 promise(.failure(NSError(domain: "", code: -1, userInfo: nil))) } else { promise(.success(1)) } } publisher.retry(2) .sink(receiveCompletion: { _ in }, receiveValue: { print($0) }) ``` 以上是一些Combine框架中常见的操作符,它们可以帮助开发者更灵活地处理异步事件流。更多的操作符和详细用法可以在苹果的官方文档中找到[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值