RxAndroid使用文档(New)

1 概述

RxJava 一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库.响应式编程是一种基于异步数据流概念的编程模式。数据流就像一条河:它可以被观测,被过滤,被操作,或者为新的消费者与另外一条流合并为一条新的流。

Rx并不是一种新的语言,而是一种普通的Java模式,类似于观察者模式(Observer Pattern),可以将它看作一个普通的Java类库。而RxAndroid是RxJava的一个针对Android平台的扩展,主要用于 Android 开发。

1.1 RxJava 有几个基本概念:


  1. Observable 发射源 (可观察者,即被观察者)
  2. Observer 接收源(观察者)
  3. Subscriber:Subscriber实现了Observer和Subscription接口,所以比Observer多了一个方法unsubscribe( ),用来取消订阅。
  4. Subject:一个比较特殊的对象,既可充当发射源,也可充当接收源
  5. Subscription :Observable调用subscribe( )方法返回的对象,同样有unsubscribe()方法,可以用来取消订阅事件;
  6. Action0:RxJava中的一个接口,它只有一个无参call()方法,且无返回值,同样还有Action1,Action2…Action9等,Action1封装了含有 1 个参的call()方法,即call(T t),Action2封装了含有 2 个参数的call方法,即call(T1 t1,T2 t2),以此类推;
  7. Func0:与Action0非常相似,也有call()方法,但是它是有返回值的,同样也有Func0、Func1…Func9;
  8. subscribe() 订阅方法,subscribe() 之后, Observable 会持有 Subscriber 的引用,这个引用如果不能及时被释放,将有内存泄露的风险。
  9. unsubscribe() 取消订阅方法,在这个方法被调用后,Subscriber 将不再接收事件。要在不再使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。

Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。

1.2 RxJava的优点

  1. 创建:Rx可以方便的创建事件流和数据流
  2. 组合:Rx使用查询式的操作符组合和变换数据流
  3. 监听:Rx可以订阅任何可观察的数据流并执行操作
  4. 函数式风格:对可观察数据流使用无副作用的输入输出函数,避免了程序里错综复杂的状态
  5. 简化代码:Rx的操作符通通常可以将复杂的难题简化为很少的几行代码
  6. 异步错误处理:传统的try/catch没办法处理异步计算,Rx提供了合适的错误处理机制
  7. 轻松使用并发:Rx的Observables和Schedulers让开发者可以摆脱底层的线程同步和各种并发问题

2 Observable

Observable 即被观察者,它决定什么时候触发事件以及触发怎样的事件。

一个Observable可以发出零个或者多个事件,直到结束或者出错。每发出一个事件,就会调用它subscribe的Subscriber的onNext方法,最后调用Subscriber.onCompleted()完成或者Subscriber.onError()出错而结束。

下面看看RxJava提供的创建Observable的方法:

2.1 create

新建一个Observables.create方法中传入了一个 OnSubscribe 对象作为参数,OnSubscribe 会被存储在返回的 Observable 对象中,它的作用相当于一个计划表。当 Observable 被订阅(subscribe)的时候,OnSubscribe 的 call() 方法会自动被调用,事件序列就会依照call中设定依次触发.

public void testCreate(View view) {
   mObservable = Observable.create(new Observable.OnSubscribe<String>() {
       @Override
       public void call(Subscriber<? super String> subscriber) {
           if (!subscriber.isUnsubscribed()) {
               subscriber.onNext("Hello");
               subscriber.onNext("World");
               subscriber.onCompleted();
           }
       }
   });
}

2.1 subscribe()订阅

由于创建后需要订阅了才能看到效果,这里初步看看订阅方法。subscribe()注册 SubscriberObservable .

subscribe()方法做了三件事:

  1. 调用 Subscriber.onStart()
  2. 调用 Observable 中的 OnSubscribe.call(Subscriber)
  3. 将传入的 Subscriber 作为 Subscription 返回
public void testSubscribe(View view) {
   if (mObservable != null) {
       mObservable.subscribe(new Subscriber<String>() {
           @Override
           public void onStart() {
           /** start方法不是必须的,call方法之前调用。
             * 在subscribe 所发生的线程被调用,不能指定线程
             */
               Log.e("testSubscribe", "onStart" + Thread.currentThread().getId());
               super.onStart();
           }

           @Override
           public void onCompleted() {
               Log.e("testSubscribe", "onCompleted" + Thread.currentThread().getId());
           }

           @Override
           public void onError(Throwable e) {
                e.printStackTrace();
           }

           @Override
           public void onNext(String s) {
               Log.e("testSubscribe", s + Thread.currentThread().getId());
           }
       });
   }
}

2.2 forEach

forEach方法是简化版的subscribe,无返回值。通过 forEach 可以处理 Observable 每个发射出来的数据。且是非阻塞执行的。forEach一般用于遍历所有元素,然后处理。

public void forEach(View v) {
    Observable.interval(500, TimeUnit.MILLISECONDS)
            .take(6)
            .forEach(LogUtils::e);
    LogUtils.e("over");
}

非阻塞的,所以先打印出后面的内容。

02-18 00:50:16.921 15095-15095/com.felix.testrxjava E/LogUtils: over
02-18 00:50:17.420 15095-15290/com.felix.testrxjava E/LogUtils:  0
02-18 00:50:17.920 15095-15290/com.felix.testrxjava E/LogUtils:  1
02-18 00:50:18.420 15095-15290/com.felix.testrxjava E/LogUtils:  2
02-18 00:50:18.919 15095-15290/com.felix.testrxjava E/LogUtils:  3
02-18 00:50:19.420 15095-15290/com.felix.testrxjava E/LogUtils:  4
02-18 00:50:19.919 15095-15290/com.felix.testrxjava E/LogUtils:  5

2.3 just(T…)

just()方法可以传入一到九个参数,它们会按照传入的参数的顺序来发射它们。just()方法也可以接受列表或数组,它将会发射整个列表。通常,当我们想发射一组已经定义好的值时会用到它。但是如果我们的函数不是时变性的,我们可以用just来创建一个更有组织性和可测性的代码库。

 public void testJust(View view) {
        mObservable = Observable.just("hello", "World");
    }

2.4 from(T[] t) / from(Iterable

Observable.from(Executors.newFixedThreadPool(3).submit(new Callable<String>() {
       @Override
       public String call() throws Exception {
           Thread.sleep(5000);
           return "result";
       }
   }))
      .subscribe(new Action1<String>() {
          @Override
          public void call(String s) {
              Log.e("", s);
          }
      });
}

2.5 defer(Func0

 public void testDefer(View view) {
   count = 1;
   //just方法
   Observable<Integer> justObservable = Observable.just(count);
   count = 2;
   //just的订阅
   justObservable.subscribe(new Action1<Integer>() {
       @Override
       public void call(Integer integer) {
           Log.e("testDefer", "just   " + integer);
       }
   });
   count = 3;
   //defer方法
   Observable<Integer> testDefer = Observable.defer(new Func0<Observable<Integer>>() {
       @Override
       public Observable<Integer> call() {
           //注意此处的call方法没有Subscriber参数
           return Observable.just(count);
       }
   });
   count = 4;
   //defer订阅
   testDefer.subscribe(new Subscriber<Integer>() {
       @Override
       public void onCompleted() {
           Log.e("testDefer", "onCompleted");
       }

       @Override
       public void onError(Throwable e) {
           Log.e("testDefer", "onError   " + e.getMessage());
       }

       @Override
       public void onNext(Integer i) {
           Log.e("testDefer", "defer " + i);
       }
   });
   count = 5;
   //defer订阅2
   testDefer.subscribe(new Action1<Integer>() {
       @Override
       public void call(Integer integer) {
           Log.e("testDefer", "Action1 defer " + integer);
       }
   });
}

以上示例将just和defer放在一起做了一个对比。我们看看打印的值。just等操作符是在创建的时候就已经生成了Observable,而defer是在subscribe的时候才创建,而且每次订阅都会新创建一个,以保证当前使用的是最新的值。

com.felix.testrxjava E/testDefer: just   1
com.felix.testrxjava E/testDefer: defer 4
com.felix.testrxjava E/testDefer: onCompleted
com.felix.testrxjava E/testDefer: Action1 defer 5

2.6 interval/timeInterval

  1. interval创建一个按固定时间间隔发射整数序列的Observable,可用作定时器.interval()有一个三个参数的重载方法,可以传入Scheduler调度器,默认使用的是Schedulers.computation()。

    public void testInterval(View view) {
        //每隔2s发送一次
       final Subscription subscription = Observable.interval(2, TimeUnit.SECONDS)
               .subscribe(new Action1<Long>() {
                   @Override
                   public void call(Long aLong) {
                       Log.e("testInterval", "  " + aLong);
                   }
               });
    
        //延迟15s取消订阅
       new Handler().postDelayed(new Runnable() {
           @Override
           public void run() {
               subscription.unsubscribe();
           }
       }, 15 * 1000);
    }
  2. timeInterval将原始Observable转换为另一个Obserervable,后者发射一个标志替换前者的数据项,这个标志表示前者的两个连续发射物之间流逝的时间长度。新的Observable的第一个发射物表示的是在观察者订阅原始Observable到原始Observable发射它的第一项数据之间流逝的时间长度。不存在与原始Observable发射最后一项数据和发射onCompleted通知之间时长对应的发射物。timeInterval默认在immediate调度器上执行,你可以通过传参数修改。

    public void timeInterval(View view) {
        Observable.create(subscriber -> {
            for (int i = 0; i < 5; i++) {
                SystemClock.sleep(i * 1000);
                subscriber.onNext("aaaa " + i);
            }
            subscriber.onCompleted();
        }).timeInterval().cast(TimeInterval.class)
                .subscribe(x -> Log.e("timeInterval", x.getIntervalInMilliseconds() + "++" + x.getValue()));
    }

    看看输出,getIntervalInMilliseconds,返回的间隔的毫秒值,getValue返回的是上一个Observable抛出来的值。

    02-16 22:47:03.748 21569-21569/com.felix.testrxjava E/timeInterval: 0++aaaa 0
    02-16 22:47:04.749 21569-21569/com.felix.testrxjava E/timeInterval: 1001++aaaa 1
    02-16 22:47:06.749 21569-21569/com.felix.testrxjava E/timeInterval: 2000++aaaa 2
    02-16 22:47:09.750 21569-21569/com.felix.testrxjava E/timeInterval: 3001++aaaa 3
    02-16 22:47:13.750 21569-21569/com.felix.testrxjava E/timeInterval: 4000++aaaa 4

2.7 range

创建一个发射特定整数序列的Observable:第一个参数为起始值;第二个为发送的个数,如果为0则不发送,负数则抛异常,大于int类型的最大值也会抛异常。

/**
     * 发射从1开始的10个数字
     *
     * @param view
     */
public void testRange(View view) {
   Observable.range(1, 10)
      .subscribe(new Action1<Integer>() {
          @Override
          public void call(Integer integer) {
              Log.e("testRange", " " + integer);
          }
      });
}

2.8 timer

创建一个Observable,它在一个给定的延迟后发射一个特殊的值(一般是0),等同于Android中Handler的postDelay()。

timer()有一个三个参数的重载方法,可以传入Scheduler调度器,默认使用的是Schedulers.computation()。

public void testTimer(View view) {
   Observable.timer(2, TimeUnit.SECONDS)
      .subscribe(new Action1<Long>() {
          @Override
          public void call(Long aLong) {
              Log.e("testRange", " " + aLong);
          }
      });
}

2.9 repeat

创建重复发射特定的数据或数据序列的Observable

2.10 start

它接受一个函数作为参数,调用这个函数获取一个值,然后返回一个会发射这个值给后续观察者的Observable。Start操作符的多种RxJava实现都属于可选的rxjava-async模块。

注意:这个函数只会被执行一次,即使多个观察者订阅这个返回的Observable。

2.11 empty

不调用onNext(),直接调用onComplete(),这里onStart方法也会调用。

 public void testEmpty(View view) {
   mObservable = Observable.empty();
}

2.12 never

创建一个不发射数据并且也永远不会结束的Observable。只有onStart方法也会被调用。

 public void testNever(View view) {
   mObservable = Observable.never();
   mObservable.subscribe(new Subscriber<String>() {

       @Override
       public void onStart() {
           Log.e("testNever", "onStart");
       }

       @Override
       public void onCompleted() {
           Log.e("testNever", "onCompleted");
       }

       @Override
       public void onError(Throwable e) {
           e.printStackTrace();
       }

       @Override
       public void onNext(String s) {
           Log.e("testNever", "onNext  " + s);
       }
   });
}

2.13 error

创建一个不发射数据并且以错误结束的Observable。 只会回调onStart和onError方法。

 public void testError(View view) {
   mObservable = Observable.error(new Exception("error test"));
}

2.14 using

using操作符让你可以指示Observable创建一个只在它的生命周期内存在的资源,当Observable终止时这个资源会被自动释放。

using操作符接受三个参数:

  1. Func0,一个用户创建一次性资源的工厂函数
  2. Func1,一个用于创建Observable的工厂函数
  3. Action1,一个用于释放资源的函数

当一个观察者订阅using返回的Observable时,using将会使用Observable工厂函数创建观察者要观察的Observable,同时使用资源工厂函数创建一个你想要创建的资源。当观察者取消订阅这个Observable时,或者当观察者终止时(无论是正常终止还是因错误而终止),using使用第三个函数释放它创建的资源。

我们来看一个例子

public void using(View view) {
    Observable.using(
            () -> new TestUsingThread(),
            t -> Observable.timer(10, TimeUnit.SECONDS),
            resource -> resource.stopThread()
    ).subscribe(
            LogUtils::e,
            e -> e.printStackTrace(),
            () -> LogUtils.e("completed")
    );
}

class TestUsingThread extends Thread {
    private volatile boolean flag = true;
    int index = 0;
    public void stopThread() {
        this.flag = false;
    }
    public TestUsingThread() {
        this.start();
    }
    @Override
    public void run() {
        while (flag) {
            Log.e("=====", index++ + "");
            SystemClock.sleep(index * 1000);
        }
    }
}

测试线程一直运行,知道时间达到10s,调用关闭方法关闭线程,这里看到线程停止运行了。用来关闭资源很好

02-18 00:39:46.087 29094-29417/com.felix.testrxjava E/=====: 0
02-18 00:39:47.088 29094-29417/com.felix.testrxjava E/=====: 1
02-18 00:39:49.088 29094-29417/com.felix.testrxjava E/=====: 2
02-18 00:39:52.088 29094-29417/com.felix.testrxjava E/=====: 3
02-18 00:39:56.090 29094-29417/com.felix.testrxjava E/=====: 4
02-18 00:39:56.103 29094-29419/com.felix.testrxjava E/LogUtils:  0
02-18 00:39:56.104 29094-29419/com.felix.testrxjava E/LogUtils: completed

3 Single

Single类似于Observable,不同的是,它总是只发射一个值,或者一个错误通知,而不是发射一系列的值。订阅Single只需要如下两个方法, 需要注意Single是没有onStart方法.

onSuccess - Single发射单个的值到这个方法.
onError - 如果无法发射需要的值,Single发射一个Throwable对象到这个方法

3.1 创建

Single的创建方式和Observable基本类似,Observable支持的方法,Single基本都支持。

使用示例如下:

 public void testSingle(View view) {
   Single<String> single = Single.create(new Single.OnSubscribe<String>() {
       @Override
       public void call(SingleSubscriber<? super String> singleSubscriber) {
           if (!singleSubscriber.isUnsubscribed()) {
               if (SystemClock.currentThreadTimeMillis() % 2 == 0) {
                   singleSubscriber.onSuccess("Hello");
                   singleSubscriber.onSuccess("World");
               } else {
                   singleSubscriber.onError(new Exception("sth error"));
               }
           }
       }
   });

   single.subscribe(new SingleSubscriber<String>() {

       @Override
       public void onSuccess(String value) {
           Log.e("###", value);
       }

       @Override
       public void onError(Throwable error) {
           error.printStackTrace();
       }
   });
}

3.2 concatWith: Single转化为Observable

4 Observer

Observer 即观察者,它决定事件触发的时候将有怎样的行为。

Observer 是一个接口,包含了三个方法

  1. onNext() 普通事件的回调。

  2. onCompleted(): 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。

  3. onError(): 事件队列异常。在事件处理过程中出异常时,onError() 会被触发,同时队列自动终止,不允许再有事件发出。

在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,并且是事件序列中的最后一个。需要注意的是,onCompleted() 和 onError() 二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。

一般不会直接使用Observer接口,而是使用实现了其接口的抽象类Subscriber,Observer用法如下:

public void testObserver(View view) {
   Observable.just(12)
           .subscribe(new Observer<Integer>() {
               @Override
               public void onCompleted() {
                   Log.e(TAG, "" + "onCompleted");
               }

               @Override
               public void onError(Throwable e) {
                   e.printStackTrace();
               }

               @Override
               public void onNext(Integer integer) {
                   Log.e(TAG, "" + integer);
               }
           });
}

5 Subscriber

Subscriber 是一个实现了 Observer 和 Subscription 两个接口的抽象类。 Subscriber 对 Observer 接口进行了一些扩展,但他们的基本使用方式是完全一样的:

Subscriber与Observer相比

  1. Subscriber多了一个onStart方法
  2. Subscriber多了一个unsubscribe()方法,用于取消订阅
  3. Subscriber多了一个isUnsubscribed()方法,用于判断订阅状态

6 Subject

Subject 是一个神奇的对象,它可以是一个Observable同时也可以是一个Observer。Subject是一个抽象类,继承了Observable的同时也实现了Observer接口。
常用的Subject实现类有以下几个:

6.1 PublishSubject

PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者。需要注意的是,PublishSubject可能会一创建完成就立刻开始发射数据(除非你可以阻止它发生),因此这里有一个风险:在PublishSubject被创建后到有观察者订阅它之前这个时间段内,一个或多个数据可能会丢失。

public void publishSubject(View view) {
   //create方法是无参的,需要通过后续的onNext,onComplete,onError等方法发送数据
   PublishSubject<String> subject = PublishSubject.create();
   subject.onNext("1.  Hello World");
   subject.subscribe(new Subscriber<String>() {
       @Override
       public void onCompleted() {
           Log.e("PublishSubject", "onCompleted");
       }

       @Override
       public void onError(Throwable e) {
           Log.e("PublishSubject", "onError    " + e.getMessage());

       }

       @Override
       public void onNext(String s) {
           Log.e("PublishSubject", "onNext " + s);
       }
   });
   subject.onNext("2.This is Felix");
   subject.onCompleted();
}

以上demo打印结果如下,只有订阅以后的消息推送才会接收到,这里需要注意订阅之前的subject.onCompleted/subject.onError回调,也会在订阅之后收到,标志此Observable结束

com.felix.testrxjava E/PublishSubject: onNext 2.This is Felix
com.felix.testrxjava E/PublishSubject: onCompleted

PublishSubject一般用于创建连接Observables并且同时可被观测的实体。比如为公共资源创建独立、抽象或更易观测的点这种场景。例如如下场景,我们需要监测一个内部请求的结果,不管成功失败。

//创建一个PublishSubject用于接收最终的结果
final PublishSubject<Boolean> publishSubject = PublishSubject.create();
publishSubject.subscribe(new Action1<Boolean>() {
     @Override
     public void call(Boolean aBoolean) {
         //最终的结果在这里接收监听并处理
         Log.e("PublishSubject", "subscribe-- " + aBoolean);
     }
});
    //创建一个私有的Observable,只有内部的变量才能访问到
Observable.create(new Observable.OnSubscribe<Integer>() {
     @Override
     public void call(Subscriber<? super Integer> subscriber) {
         for (int i = 0; i < 10; i++) {
             subscriber.onNext(i);
         }
         subscriber.onCompleted();
     }
}).doOnCompleted(new Action0() {
     当Observable结束时要会调用这里
     @Override
     public void call() {
         publishSubject.onNext(true);
     }
}).subscribe();//空的订阅表示不关注中间过程

以上运行的结果,就达到了只监控最终结果的目的。

com.felix.testrxjava E/PublishSubject: subscribe-- true

6.2 BehaviorSubject

当观察者订阅BehaviorSubject时,它开始发射原始Observable最近发射的数据(如果此时还没有收到任何数据,它会发射一个默认值),然后继续发射订阅后的数据流。

public void behaviorSubject(View view) {
   Integer integer = 12;
   BehaviorSubject<Integer> behaviorSubject =BehaviorSubject.create(integer);       
   behaviorSubject.subscribe(new Action1<Integer>() {
       @Override
       public void call(Integer integer) {
           Log.e("BehaviorSubject1", "1.  " + integer);
       }
   });
   behaviorSubject.onNext(11);
   behaviorSubject.onNext(23);
   behaviorSubject.onNext(58);
   behaviorSubject.subscribe(new Action1<Integer>() {
       @Override
       public void call(Integer integer) {
           Log.e("BehaviorSubject2", "2.  " + integer);
       }
   });
}

以上例子,BehaviorSubject.create(),不传参数的时候,是不会发送默认值的。输出如下:

com.felix.testrxjava E/BehaviorSubject1: 1.  11
com.felix.testrxjava E/BehaviorSubject1: 1.  23
com.felix.testrxjava E/BehaviorSubject1: 1.  58
com.felix.testrxjava E/BehaviorSubject2: 2.  58

带一个参数的时候,其内部会默认认为此参数是默认值的,也就会发送默认值即使这个参数为null。我们看看源码

//无参方法,默认第一个参数是null,第二个参数是false
 public static <T> BehaviorSubject<T> create() {
     return create(null, false);
}

//带有默认值的方法,默认第二个参数是true
public static <T> BehaviorSubject<T> create(T defaultValue) {
        return create(defaultValue, true);
}

private static <T> BehaviorSubject<T> create(T defaultValue, boolean hasDefault) {
   final SubjectSubscriptionManager<T> state = new SubjectSubscriptionManager<T>();
    if (hasDefault){
          state.setLatest(NotificationLite.instance().next(defaultValue));
   }
   state.onAdded = new Action1<SubjectObserver<T>>() {
       @Override
       public void call(SubjectObserver<T> o) {
           o.emitFirst(state.getLatest(), state.nl);
       }    
   };
   state.onTerminated = state.onAdded;
   return new BehaviorSubject<T>(state, state); 
}

6.3 ReplaySubject

ReplaySubject会缓存它所订阅的所有数据,向任意一个订阅它的观察者重发。

public void replaySubject(View view) {
   ReplaySubject<Integer> subject = ReplaySubject.create();
   for (int i = 0; i < 3; i++) {
       subject.onNext(i);
   }
   subject.subscribe(new Subscriber<Integer>() {
       @Override
       public void onCompleted() {
           Log.e("replaySubject", "onCompleted");
       }

       @Override
       public void onError(Throwable e) {
           Log.e("replaySubject", "onError " + e.getMessage());
       }

       @Override
       public void onNext(Integer integer) {
           Log.e("replaySubject", "onError " + integer);
       }
   });
   for (int i = 0; i < 5; i++) {
       subject.onNext(i);
   }
   subject.subscribe(new Action1<Integer>() {
       @Override
       public void call(Integer integer) {
           Log.e("replaySubject2", "onError2   " + integer);
       }
   });
}

以上执行的结果将都打印出所有循环的数据,由于没有执行取消订阅unsubscribe方法。

com.felix.testrxjava E/replaySubject: onError 0
com.felix.testrxjava E/replaySubject: onError 1
com.felix.testrxjava E/replaySubject: onError 2
com.felix.testrxjava E/replaySubject: onError 0
com.felix.testrxjava E/replaySubject: onError 1
com.felix.testrxjava E/replaySubject: onError 2
com.felix.testrxjava E/replaySubject: onError 3
com.felix.testrxjava E/replaySubject: onError 4
com.felix.testrxjava E/replaySubject: onError2 0
com.felix.testrxjava E/replaySubject: onError2 1
com.felix.testrxjava E/replaySubject: onError2 2
com.felix.testrxjava E/replaySubject: onError2 0
com.felix.testrxjava E/replaySubject: onError2 1
com.felix.testrxjava E/replaySubject: onError2 2
com.felix.testrxjava E/replaySubject: onError2 3
com.felix.testrxjava E/replaySubject: onError2 4

如果你把ReplaySubject当作一个观察者使用,注意不要从多个线程中调用它的onNext方法(包括其它的on系列方法),这可能导致同时(非顺序)调用,这会违反Observable协议,给Subject的结果增加了不确定性。

6.4 AsyncSubject

一个AsyncSubject只在原始Observable完成后,发射来自原始Observable的最后一个值。(如果原始Observable没有发射任何值,AsyncObject也不发射任何值)它会把这最后一个值发射给任何后续的观察者。

public void asyncSubject(View view) {
   AsyncSubject<Integer> subject = AsyncSubject.create();
   subject.subscribe(new Action1<Integer>() {
       @Override
       public void call(Integer integer) {
           Log.e("asyncSubject", "1. " + integer);
       }
   });
   for (int i = 0; i < 3; i++) {
       subject.onNext(i);
   }
   //onCompleted方法调用后才会触发订阅的回调,否则无回调。
   subject.onCompleted();
   subject.subscribe(new Action1<Integer>() {
       @Override
       public void call(Integer integer) {
           Log.e("asyncSubject2", "2. " + integer);
       }
   });
}

输出结果如下

com.felix.testrxjava E/asyncSubject: 1. 2
com.felix.testrxjava E/asyncSubject2: 2. 2

说明

  1. onCompleted方法调用后才会触发订阅的回调,否则无回调。
  2. 无论何时订阅,都会回调,而且都只会回调最终结果。

6.5 SerializedSubject

多个线程中调用Subject的onNext方法(包括其它的on系列方法),可能导致同时(非顺序)调用Subscriber,这会违反Observable协议,给Subject的结果增加了不确定性。 要避免此类问题,你可以将 Subject 转换为一个 SerializedSubject。SerializedSubject保证了同一时刻只有一个线程可以调用其方法发射数据。

我们看看传统的方式

public void serializedSubject(View view) {
   final PublishSubject<String> subject = PublishSubject.create();
   subject.subscribe(new Action1<String>() {
       @Override
       public void call(String s) {
           Log.e("serializedSubject", s);
           pos++;
       }
   });
   ExecutorService service = Executors.newFixedThreadPool(3);
   for (int i = 0; i < 3; i++) {
       service.submit(new Runnable() {
           @Override
           public void run() {
               for (int j = 0; j < 3; j++) {
                   SystemClock.sleep(300);
            subject.onNext(Thread.currentThread().getName() + "    " + pos);
               }
           }
       });
   }
   service.shutdown();
}

输出结果如下,我们看到,线程1和线程2同时访问了onNext方法,这里就导致了输出两个一样的结果 3

serializedSubject: pool-1-thread-1    0
serializedSubject: pool-1-thread-2    1
serializedSubject: pool-1-thread-3    2
serializedSubject: pool-1-thread-1    3
serializedSubject: pool-1-thread-2    3
serializedSubject: pool-1-thread-3    5
serializedSubject: pool-1-thread-1    6
serializedSubject: pool-1-thread-2    7
serializedSubject: pool-1-thread-3    8

如果我们加上serializedSubject装饰一下

public void serializedSubject(View view) {
   final PublishSubject<String> subject = PublishSubject.create();
   final SerializedSubject serializedSubject = new SerializedSubject(subject);
   serializedSubject.subscribe(new Action1<String>() {
       @Override
       public void call(String s) {
           Log.e("serializedSubject", s);
           pos++;
       }
   });
   ExecutorService service = Executors.newFixedThreadPool(3);
   for (int i = 0; i < 3; i++) {
       service.submit(new Runnable() {
           @Override
           public void run() {
               for (int j = 0; j < 3; j++) {
                   SystemClock.sleep(300);
          serializedSubject.onNext(Thread.currentThread().getName() + "    " + pos);
               }
           }
       });
   }
   service.shutdown();
}

我们再看看输出,如下:无论重试多少次,都会发现不会重复了。加了SerializedSubject的装饰,就不会同时又多个线程访问onNext方法了。

serializedSubject: pool-1-thread-1    0
serializedSubject: pool-1-thread-2    1
serializedSubject: pool-1-thread-3    2
serializedSubject: pool-1-thread-1    3
serializedSubject: pool-1-thread-2    4
serializedSubject: pool-1-thread-3    5
serializedSubject: pool-1-thread-1    6
serializedSubject: pool-1-thread-2    7
serializedSubject: pool-1-thread-3    8

这里还需要注意,SerializedSubject用来包装其他Subject才有这种效果,直接调用create/just等方法的话,将会吧SerializedSubject转化为Observable。

6.6 Subject总结

  1. Subject没法指定异步线程,更像是EventBus通过订阅来实现事件通知。
  2. just(T)、from(T)、create(T)会把Subject转换为Obserable
  3. Subject.asObservable也会返回一个Obserable

7 Scheduler

如果你想给Observable操作符链添加多线程功能,你可以指定操作符(或者特定的Observable)在特定的调度器(Scheduler)上执行。

RxJava中常见的调度器:

调度器类型效果
Schedulers.computation()用于计算任务,如事件循环或和回调处理,
不要用于IO操作(IO操作请使用Schedulers.io())
默认线程数等于处理器的数量
Schedulers.from(executor)使用指定的Executor作为调度器
Schedulers.immediate( )在当前线程立即开始执行任
Schedulers.io( )用于IO密集型任务,如异步阻塞IO操作,
这个调度器的线程池会根据需要增长;
对于普通的计算任务,请使用Schedulers.computation();
Schedulers.io( )默认是一个CachedThreadScheduler,
很像一个有线程缓存的新线程调度器
Schedulers.newThread( )为每个任务创建一个新线程
Schedulers.trampoline( )当其它排队的任务完成后,在当前线程排队开始执行

使用ObserveOn和SubscribeOn操作符,你可以让Observable在一个特定的调度器上执行,ObserveOn指示一个Observable在一个特定的调度器上调用观察者的onNext, onError和onCompleted方法,SubscribeOn更进一步,它指示Observable将全部的处理过程(包括发射数据和通知)放在特定的调度器上执行。

7.1 subscribeOn

subscribeOn改变了Observable本身产生事件的schedule以及发出事件后相关处理事件的程序所在的schedule,subscribeOn()主要改变的是订阅的线程,即call()执行的线程.

subscribeOn则是一次性的,无论在什么地方调用,总是从改变最原始的Observable开始影响整个Observable的处理。

 public void subscribeOn(View view) {
    Observable.create(subscriber -> {
        Log.e("call", "call   " + Thread.currentThread().getId());
        if (new Random().nextBoolean()) {
            subscriber.onNext("hello");
            subscriber.onCompleted();
        } else {
            subscriber.onError(new Exception("error"));
        }
    }).cast(String.class)
            .subscribeOn(Schedulers.newThread())
            .subscribe(new Subscriber<String>() {
                @Override
                public void onStart() {
                    Log.e("onStart", "onStart   " + Thread.currentThread().getId());
                }
                @Override
                public void onCompleted() {
                    Log.e("onCompleted", "onCompleted   " + Thread.currentThread().getId());
                }
                @Override
                public void onError(Throwable e) {
                    Log.e("onError", "onError   " + Thread.currentThread().getId());
                }
                @Override
                public void onNext(String s) {
                    Log.e("onNext", "onNext   " + Thread.currentThread().getId());
                }
            });
}

看看返回值,切换了call的线程以后,onNext/onCompleted/onError执行的线程都跟着变成了切换后的线程。可以将切换的线程注释掉,会发现所有的线程都变成了1,也就是默认都在当前线程运行。这里需要注意:onStart方法默认在Observable执行的线程运行(当前1为主线程)

02-15 18:49:33.903 10731-10731/com.felix.testrxjava E/onStart: onStart   1
02-15 18:49:33.907 10731-11732/com.felix.testrxjava E/call: call   936
02-15 18:49:33.907 10731-11732/com.felix.testrxjava E/onNext: onNext   936
02-15 18:49:33.907 10731-11732/com.felix.testrxjava E/onCompleted: onCompleted   936

//点击了两次,随机函数产生了两种结果
02-15 18:49:52.701 10731-10731/com.felix.testrxjava E/onStart: onStart   1
02-15 18:49:52.702 10731-12100/com.felix.testrxjava E/call: call   937
02-15 18:49:52.702 10731-12100/com.felix.testrxjava E/onError: onError   937

7.2 ObserveOn

ObserveOn 改变了对发出事件后相关处理事件的程序所在的schedule。observeOn()主要改变的是发送的线程,即onNext, onCompleted, onError方法执行的线程。

ObserveOn可以多次调用,多次改变不同的接受者所在的schedule,对调用这个函数之后的Observable造成影响

注意:当遇到一个异常时ObserveOn会立即向前传递这个onError终止通知,它不会等待慢速消费的Observable接受任何之前它已经收到但还没有发射的数据项。这可能意味着onError通知会跳到(并吞掉)原始Observable发射的数据项前面。

7.3 unsubscribeOn

有些 Observable 会依赖一些资源,当该 Observable 完成后释放这些资源。如果释放资源比较耗时的话,可以通过 unsubscribeOn 来指定 释放资源代码执行的线程。

7.4 Scheduler.Worker

7.5

8 操作符之过滤操作

8.1 Filter/ofType

过滤,过滤掉没有通过谓词测试的数据项,只发射通过测试的

java
public void filter(View v) {
Observable.just(12, 3, 4, 5, 7, 9, 8)
.filter(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer integer) {
return integer < 6;
}
}).subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.e("filter", integer + "");
}
});
}

ofType是filter操作符的一个特殊形式。它过滤一个Observable只返回指定类型的数据。

ofType默认不在任何特定的调度器上指定。

8.2 take/takeLast/takeLastBuffer

只保留前面/后面几条数据。

值得注意的是因为takeLast()方法只能作用于一组有限的序列(发射元素),它只能应用于一个完整的序列。

public void takeLast(View view) {
   Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
           .take(7).takeLast(4).subscribe(new Action1<Integer>() {
       @Override
       public void call(Integer integer) {
           Log.e("take", integer + "");
       }
   });
}

takeLastBuffer,它和takeLast类似,,唯一的不同是它把所有的数据项收集到一个List再发射,而不是依次发射一个。

8.3 distinct/distinctUntilChanged

distinct()作用于一个完整的序列,然后得到重复的过滤项,它需要记录每一个发射的值。如果你在处理一大堆序列或者大的数据记得关注内存使用情况。

distinctUntilChanged 在一个可观测序列发射一个不同于之前值的一个新值。

public void distinct(View view){
   Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
           .take(3).repeat(4).distinct().subscribe(new Action1<Integer>() {
       @Override
       public void call(Integer integer) {
           Log.e("distinct", integer + "");
       }
   });
}

public void distinctUntilsChanged(View view){
   Observable.just(2,2,3,2,4,5,6,5,3,3).distinctUntilChanged()
           .subscribe(new Action1<Integer>() {
               @Override
               public void call(Integer integer) {
                   Log.e("distinctUntilsChanged", integer + "");
               }
           });
}

8.4 first/last/elementAt

first 只发送第一个数据
firstOrDefault 只发射第一项数据,如果Observable为空就发射默认值
last 只发送最后一个数据
lastOrDefault 只发射最后一项数据,如果Observable为空就发射默认值
elementAt(N) 只发送第N个数据
elementAtOrDefault(N) 只发送第N个数据,如果Observable为空或者不存在第N个数据就发射默认值

8.5 sample/throttleLast

定期发射Observable最近的数据

8.6 throttleFirst

定期发射Observable发射的第一项数据

8.7 timeout

使用timeout()函数来监听源可观测序列,就是在我们设定的时间间隔内如果没有得到一个值则发射一个错误。我们可以认为timeout()为一个Observable的限时的副本。如果在指定的时间间隔内Observable不发射值的话,它监听的原始的Observable时就会触发onError()函数

8.8 debounce/throttleWithTimeout

过滤掉由Observable发射的速率过快的数据;如果在一个指定的时间间隔过去了仍旧没有发射一个,那么它将发射最后的那个。

debounce()函数开启一个内部定时器,如果在这个时间间隔内没有新的数据发射,则新的Observable发射出最后一个数据:

8.9 ignoreElements

丢弃所有的正常数据,只发射错误或完成通知

8.10 skip/SkipLast

使用Skip操作符,你可以忽略Observable’发射的前N项数据,只保留之后的数据。

使用SkipLast操作符修改原始Observable,你可以忽略Observable’发射的后N项数据,只保留前面的数据。

skip/skipLast的这个变体默认在computation调度器上执行,但是你可以使用第三个参数指定其它的调度器。

9 变换

RxJava提供了几个mapping函数:map(),flatMap(),concatMap(),flatMapIterable()以及switchMap().所有这些函数都作用于一个可观测序列,然后变换它发射的值,最后用一种新的形式返回它们。

9.1 map

对序列的每一项都应用一个函数来变换Observable发射的数据序列

9.2 flatMap/concatMap/flatMapIterable

将Observable发射的数据集合变换为Observables集合,然后将这些Observable发射的数据平坦化的放进一个单独的Observable

任何一个Observables发生错误的情况,flatMap/concatMap/flatMapIterable将会触发它自己的onError()函数并放弃整个链。

三者的区别是:

  1. flatMap可以交叉,也就是不能够保证在最终生成的Observable中源Observables确切的发射顺序
  2. concatMap提供了一种能够把发射的值连续在一起的铺平函数,而不是合并它们。
  3. flatMapInterable()和flatMap()很像。仅有的本质不同是它将源数据两两结成对并生成Iterable,而不是原始数据项和生成的Observables。

flatMap的例子:

public void flatMap(View view) {
   Observable.just(0, 1).flatMap(new Func1<Integer, Observable<String>>() {
       @Override
       public Observable<String> call(final Integer i) {
           if (i % 2 == 0) {
               return Observable.create(new Observable.OnSubscribe<String>() {
                   @Override
                   public void call(Subscriber<? super String> subscriber) {
                       for (int j = 0; j < 3; j++) {
                           SystemClock.sleep(500);
                           subscriber.onNext(Thread.currentThread().getName() + "--" + i + "--" + j);
                       }
                       subscriber.onCompleted();
                   }
                   //subscribeOn改变了call执行所在的线程
               }).subscribeOn(Schedulers.newThread());
           } else {
               return Observable.create(new Observable.OnSubscribe<String>() {
                   @Override
                   public void call(Subscriber<? super String> subscriber) {
                       for (int j = 0; j < 3; j++) {
                           SystemClock.sleep(500);
                           subscriber.onNext(Thread.currentThread().getName() + "++" + i + "++" + j);
                       }
                       subscriber.onCompleted();
                   }
               }).subscribeOn(Schedulers.newThread());
           }
       }
   }).subscribe(new Action1<String>() {
       @Override
       public void call(String s) {
           Log.e("flatMap", s);
       }
   });
}

其输出结果如下所示,我们看到两次的数据是一个合并操作,是无序的:

01-31 19:40:06.136 4542-4987/com.felix.testrxjava E/flatMap: RxNewThreadScheduler-1--0--0
01-31 19:40:06.136 4542-4988/com.felix.testrxjava E/flatMap: RxNewThreadScheduler-2++1++0
01-31 19:40:06.636 4542-4987/com.felix.testrxjava E/flatMap: RxNewThreadScheduler-1--0--1
01-31 19:40:06.636 4542-4988/com.felix.testrxjava E/flatMap: RxNewThreadScheduler-2++1++1
01-31 19:40:07.136 4542-4987/com.felix.testrxjava E/flatMap: RxNewThreadScheduler-1--0--2
01-31 19:40:07.137 4542-4988/com.felix.testrxjava E/flatMap: RxNewThreadScheduler-2++1++2

我们再看看concatMap

public void concatMap(View view) {
   Observable.just(0, 1).concatMap(new Func1<Integer, Observable<String>>() {
       @Override
       public Observable<String> call(final Integer i) {
           if (i % 2 == 0) {
               return Observable.create(new Observable.OnSubscribe<String>() {
                   @Override
                   public void call(Subscriber<? super String> subscriber) {
                       for (int j = 0; j < 3; j++) {
                           SystemClock.sleep(500);
                           subscriber.onNext(Thread.currentThread().getName() + "--" + i + "--" + j);
                       }
                       subscriber.onCompleted();
                   }
                   //subscribeOn改变了call执行所在的线程
               }).subscribeOn(Schedulers.newThread());
           } else {
               return Observable.create(new Observable.OnSubscribe<String>() {
                   @Override
                   public void call(Subscriber<? super String> subscriber) {
                       for (int j = 0; j < 3; j++) {
                           SystemClock.sleep(500);
                           subscriber.onNext(Thread.currentThread().getName() + "++" + i + "++" + j);
                       }
                       subscriber.onCompleted();
                   }
               }).subscribeOn(Schedulers.newThread());
           }
       }
   }).subscribe(new Action1<String>() {
       @Override
       public void call(String s) {
           Log.e("concatMap", s);
       }
   });
}

输出结果如下,我们可以看到这是一个串行的合并操作,且需要注意的是,第一个Observable的subscriber.onCompleted方法调用结束以后才会开始第二个,若第一个未调用subscriber.onCompleted,则永远不会调用第二个的onNext方法,而是一直等待

01-31 19:44:52.709 9098-9382/com.felix.testrxjava E/concatMap: RxNewThreadScheduler-3--0--0
01-31 19:44:53.211 9098-9382/com.felix.testrxjava E/concatMap: RxNewThreadScheduler-3--0--1
01-31 19:44:53.711 9098-9382/com.felix.testrxjava E/concatMap: RxNewThreadScheduler-3--0--2
01-31 19:44:54.216 9098-9407/com.felix.testrxjava E/concatMap: RxNewThreadScheduler-4++1++0
01-31 19:44:54.717 9098-9407/com.felix.testrxjava E/concatMap: RxNewThreadScheduler-4++1++1
01-31 19:44:55.217 9098-9407/com.felix.testrxjava E/concatMap: RxNewThreadScheduler-4++1++2

9.3 switchMap

和flatMap()很像,除了一点:每当源Observable发射一个新的数据项(Observable)时,它将取消订阅并停止监视之前那个数据项产生的Observable,并开始监视当前发射的这一个.

我们看一下这个例子,

java
public void switchMap(View v) {
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
subscriber.onNext(0);
SystemClock.sleep(800);
subscriber.onNext(1);
subscriber.onCompleted();
}
}).subscribeOn(Schedulers.newThread())
.switchMap(new Func1<Integer, Observable<String>>() {
@Override
public Observable<String> call(final Integer i) {
if (i % 2 == 0) {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
for (int j = 0; j < 3; j++) {
SystemClock.sleep(500);
subscriber.onNext(Thread.currentThread().getName() + "--" + i + "--" + j);
}
subscriber.onCompleted();
}
//subscribeOn改变了call执行所在的线程
}).subscribeOn(Schedulers.newThread());
} else {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
for (int j = 0; j < 3; j++) {
SystemClock.sleep(500);
subscriber.onNext(Thread.currentThread().getName() + "++" + i + "++" + j);
}
subscriber.onCompleted();
}
}).subscribeOn(Schedulers.newThread());
}
}
}).subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.e("switchMap", s);
}
});
}

其输出结果如下,我们可以看出来,当第二个订阅发出来以后,第一个订阅就结束了,不会再次调用。

java
01-31 19:52:57.919 15284-15545/com.felix.testrxjava E/switchMap: RxNewThreadScheduler-5--0--0
01-31 19:52:58.720 15284-15562/com.felix.testrxjava E/switchMap: RxNewThreadScheduler-6++1++0
01-31 19:52:59.220 15284-15562/com.felix.testrxjava E/switchMap: RxNewThreadScheduler-6++1++1
01-31 19:52:59.720 15284-15562/com.felix.testrxjava E/switchMap: RxNewThreadScheduler-6++1++2

9.4 scan

scan()函数对原始Observable发射的每一项数据都应用一个函数,计算出函数的结果值,并将该值填充回可观测序列,等待和下一次发射的数据一起使用。

 public void scan(View view) {
   Observable.range(1, 10)
           .scan((sum, value) -> sum + value)
           .subscribe(sum -> Log.e("scan", sum + ""));
}

输出结果如下,这是一个求和操作,计算1到10的和:

01-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 1
01-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 3
01-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 6
01-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 10
01-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 15
01-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 21
01-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 28
01-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 36
01-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 45
01-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 55

9.5 groupBy

GroupBy操作符将原始Observable分拆为一些Observables集合,它们中的每一个发射原始Observable数据序列的一个子序列。哪个数据项由哪一个Observable发射是由一个函数判定的,这个函数给每一项指定一个Key,Key相同的数据会被同一个Observable发射。

groupBy将原始Observable分解为一个发射多个GroupedObservable的Observable,一旦有订阅,每个GroupedObservable就开始缓存数据。因此,如果你忽略这些GroupedObservable中的任何一个,这个缓存可能形成一个潜在的内存泄露。因此,如果你不想观察,也不要忽略GroupedObservable。你应该使用像take(0)这样会丢弃自己的缓存的操作符。

如果你取消订阅一个GroupedObservable,那个Observable将会终止。如果之后原始的Observable又发射了一个与这个Observable的Key匹配的数据,groupBy将会为这个Key创建一个新的GroupedObservable。

看一个例子,将数组1-5 按 x % 2 来分组。

public void groupBy(View view) {
   Observable.range(1, 5).groupBy(a -> a % 2)
           .subscribe(new Observer<GroupedObservable<Integer, Integer>>() {
               @Override
               public void onCompleted() {

               }

               @Override
               public void onError(Throwable e) {

               }

               @Override
               public void onNext(GroupedObservable<Integer, Integer> integerIntegerGroupedObservable) {
                   integerIntegerGroupedObservable.subscribe((value -> Log.e("groupBy", "group:" + integerIntegerGroupedObservable.getKey() + " Value:" + value)));
               }
           });
}

我们可以看到,groupBy的返回值其实是一嵌套了GroupedObservable的Observable,即Observable<GroupedObservable<K, T>>,所以这里看到的是两层的订阅,外层订阅获取分组,内层订阅分组内的GroupedObservable。其中GroupedObservable.getKey()用来获取分组ID。输出结果如下:

02-01 22:35:11.274 3105-3105/com.felix.testrxjava E/groupBy: group:1 Value:1
02-01 22:35:11.274 3105-3105/com.felix.testrxjava E/groupBy: group:0 Value:2
02-01 22:35:11.274 3105-3105/com.felix.testrxjava E/groupBy: group:1 Value:3
02-01 22:35:11.275 3105-3105/com.felix.testrxjava E/groupBy: group:0 Value:4
02-01 22:35:11.275 3105-3105/com.felix.testrxjava E/groupBy: group:1 Value:5

9.6 buffer

  1. buffer(count)以列表(List)的形式发射非重叠的缓存,每一个缓存至多包含来自原始Observable的count项数据(最后发射的列表数据可能少于count项)

     Observable.range(1, 10).buffer(3)
                .subscribe(x -> Log.e("buffer(count)", x + ""));

    看看其输出:

    02-01 23:49:29.908 21934-21934/com.felix.testrxjava E/buffer(count): [1, 2, 3]
    02-01 23:49:29.908 21934-21934/com.felix.testrxjava E/buffer(count): [4, 5, 6]
    02-01 23:49:29.908 21934-21934/com.felix.testrxjava E/buffer(count): [7, 8, 9]
    02-01 23:49:29.908 21934-21934/com.felix.testrxjava E/buffer(count): [10]
  2. buffer(count, skip)从原始Observable的第一项数据开始创建新的缓存,此后每当收到skip项数据,用count项数据填充缓存:开头的一项和后续的count-1项,它以列表(List)的形式发射缓存,取决于count和skip的值,这些缓存可能会有重叠部分(比如skip < count时),也可能会有间隙(比如skip > count时)。

    Observable.range(1, 10).buffer(3, 5)
                .subscribe(x -> Log.e("buffer(count, skip>)", x + ""));
    Observable.range(1, 5).buffer(3, 2)
                .subscribe(x -> Log.e("buffer(count, skip<)", x + ""));

    看看其输出,skip大的时候,有间隙,skip小的时候有重叠:

    02-02 00:09:08.467 8665-8665/com.felix.testrxjava E/buffer(count, skip>): [1, 2, 3]
    02-02 00:09:08.467 8665-8665/com.felix.testrxjava E/buffer(count, skip>): [6, 7, 8]
    02-02 00:09:08.468 8665-8665/com.felix.testrxjava E/buffer(count, skip<): [1, 2, 3]
    02-02 00:09:08.468 8665-8665/com.felix.testrxjava E/buffer(count, skip<): [3, 4, 5]
    02-02 00:09:08.468 8665-8665/com.felix.testrxjava E/buffer(count, skip<): [5]
  3. buffer(Func0()) 当它订阅原来的Observable时,buffer(bufferClosingSelector)开始将数据收集到一个List,然后它调用bufferClosingSelector生成第二个Observable,当第二个Observable发射一个TClosing时,buffer发射当前的List,然后重复这个过程:开始组装一个新的List,然后调用bufferClosingSelector创建一个新的Observable并监视它。它会一直这样做直到原来的Observable执行完成.

  4. buffer(boundary)监视一个名叫boundary的Observable,每当这个Observable发射了一个值,它就创建一个新的List开始收集来自原始Observable的数据并发射原来的List

  5. buffer(bufferOpenings, bufferClosingSelector)监视这个叫bufferOpenings的Observable(它发射BufferOpening对象),每当bufferOpenings发射了一个数据时,它就创建一个新的List开始收集原始Observable的数据,并将bufferOpenings传递给closingSelector函数。这个函数返回一个Observable。buffer监视这个Observable,当它检测到一个来自这个Observable的数据时,就关闭List并且发射它自己的数据(之前的那个List)

  6. buffer(timespan, unit)定期以List的形式发射新的数据,每个时间段,收集来自原始Observable的数据(从前面一个数据包裹之后,或者如果是第一个数据包裹,从有观察者订阅原来的Observale之后开始)。还有另一个版本的buffer接受一个Scheduler参数,默认情况下会使用computation调度器。

    “`java
    Observable.create(new Observable.OnSubscribe() {
    @Override
    public void call(Subscriber


7. 每当收到来自原始Observable的count项数据,或者每过了一段指定的时间后,buffer(timespan, unit, count)就以List的形式发射这期间的数据,即使数据项少于count项。还有另一个版本的buffer接受一个Scheduler参数,默认情况下会使用computation调度器。

8. buffer(timespan, timeshift, unit)在每一个timeshift时期内都创建一个新的List,然后用原始Observable发射的每一项数据填充这个列表(在把这个List当做自己的数据发射前,从创建时开始,直到过了timespan这么长的时间)。如果timespan长于timeshift,它发射的数据包将会重叠,因此可能包含重复的数据项。

**注意:如果原来的Observable发射了一个onError通知,Buffer会立即传递这个通知,而不是首先发射缓存的数据,即使在这之前缓存中包含了原始Observable发射的数据**

###9.7 window

RxJava的window()函数和buffer()很像,但是它发射的是Observable而不是列表。

```java
Observable.range(1, 10).window(3)
      .subscribe(integerObservable -> integerObservable.subscribe(c -> Log.e("window(count)", "" + c)));

Observable.range(1, 10).window(3, 5)
      .subscribe(integerObservable -> integerObservable.subscribe(c -> Log.e("window(count,skip>)", "" + c)));

Observable.range(1, 10).window(3, 2)
      .subscribe(integerObservable -> integerObservable.subscribe(c -> Log.e("window(count,skip<)", "" + c)));




<div class="se-preview-section-delimiter"></div>

9.8 cast

cast()函数是map()操作符的特殊版本。它将源Observable中的每一项数据都转换为新的类型,把它变成了不同的Class。

这个类一般用于lamda表达式中的泛型被擦除后,用于将Object类型的返回值转换为真正的返回值类型。后续会有很多例子用到,这里就不举例说明了。

10 组合

10.1 merge

把两个甚至更多的Observables合并到他们发射的数据项里。使用Observable.merge(),我们可以创建新的Observable—- MergedObservable,它在单个可观测序列中发射源Observables发出的所有数据。

public void merge(View view) {
   Observable.merge(Observable.create(subscriber -> {
               for (int i = 0; i < 3; i++) {
                   subscriber.onNext(i);
                   SystemClock.sleep(300);
               }
               subscriber.onCompleted();
           }).subscribeOn(Schedulers.newThread()),
           Observable.create(subscriber -> {
               for (int i = 6; i < 8; i++) {
                   subscriber.onNext(i);
                   SystemClock.sleep(200);
               }
               subscriber.onError(new Exception("error"));
           }).subscribeOn(Schedulers.newThread()))
           .subscribe(x -> Log.e("merge", x + ""), e -> e.printStackTrace());
}




<div class="se-preview-section-delimiter"></div>

我们看看输出结果

02-03 09:19:24.415 30965-31375/com.felix.testrxjava E/merge: 0
02-03 09:19:24.415 30965-31376/com.felix.testrxjava E/merge: 6
02-03 09:19:24.615 30965-31376/com.felix.testrxjava E/merge: 7
02-03 09:19:24.715 30965-31375/com.felix.testrxjava E/merge: 1
02-03 09:19:24.816 30965-31376/com.felix.testrxjava W/System.err: java.lang.Exception: error




<div class="se-preview-section-delimiter"></div>

每个Observable抛出的错误都将会打断合并。如果你需要避免这种情况,RxJava提供了mergeDelayError(),它能从一个Observable中继续发射数据即便是其中有一个抛出了错误。当所有的Observables都完成时,mergeDelayError()将会发射onError()

merge可能会让合并的Observables发射的数据交错而concat不会让数据交错,它会按顺序一个接着一个发射多个Observables的发射物

merge是静态方法,mergeWith是对象方法。 举个例子,Observable.merge(odds,evens)等价于odds.mergeWith(evens)

10.2 zip

zip()合并两个或者多个Observables发射出的数据项,根据指定的函数Func*变换它们,并发射一个新值。

 public void zip(View view) {
   Observable.zip(Observable.interval(1000, TimeUnit.MILLISECONDS)
                   .map(key -> ((char) (97 + key)) + ""),
           interval(1500, TimeUnit.MILLISECONDS),
           (v1, v2) -> updateData(v1, v2))
           .take(8)
           .subscribe(x -> Log.e("zip", x + ""));
}

private String updateData(String v1, Long v2) {
   return v1 + v2;
}




<div class="se-preview-section-delimiter"></div>

输出结果如下

02-05 09:25:14.240 12433-13512/com.felix.testrxjava E/zip: a0
02-05 09:25:15.740 12433-13512/com.felix.testrxjava E/zip: b1
02-05 09:25:17.240 12433-13512/com.felix.testrxjava E/zip: c2
02-05 09:25:18.739 12433-13512/com.felix.testrxjava E/zip: d3
02-05 09:25:20.240 12433-13512/com.felix.testrxjava E/zip: e4
02-05 09:25:21.740 12433-13512/com.felix.testrxjava E/zip: f5
02-05 09:25:23.240 12433-13512/com.felix.testrxjava E/zip: g6
02-05 09:25:24.741 12433-13512/com.felix.testrxjava E/zip: h7




<div class="se-preview-section-delimiter"></div>

10.3 join

join()函数基于时间窗口将两个Observables发射的数据结合在一起。join有四个参数, 我们解释下join()需要的参数:

  1. 第二个Observable和源Observable结合。
  2. Func1参数:在指定的由时间窗口定义时间间隔内,源Observable发射的数据和从第二个Observable发射的数据相互配合返回的Observable。
  3. Func1参数:在指定的由时间窗口定义时间间隔内,第二个Observable发射的数据和从源Observable发射的数据相互配合返回的Observable。
  4. Func2参数:定义已发射的数据如何与新发射的数据项相结合。

说的简单点就是:join的效果类似于排列组合,把第一个数据源A作为基座窗口,他根据自己的节奏(参数1 Func1)不断发射数据元素,第二个数据源B,也按自己的节奏(参数2 Func1),它每发射一个数据,我们都把它和第一个数据源A中已经发射的数据进行一对一匹配(Func2);

举例来说,如果某一时刻B发射了一个数据 0 ,此时A已经发射了 a,b 共两个数据,那么我们的合并操作就会把1依次与a,b配对,得到数据:a0; b0;

如下

public void join(View view) {
   Observable<String> observable1 = Observable.interval(1, TimeUnit.SECONDS)
           .map(key -> ((char) (97 + key)) + "");

   Observable<Long> observable2 = Observable.interval(1, TimeUnit.SECONDS);

   observable1.join(observable2, str1 -> Observable.timer(2, TimeUnit.SECONDS),
           str2 -> Observable.timer(1, TimeUnit.SECONDS),
           this::updateData).observeOn(AndroidSchedulers.mainThread())
           .take(5).subscribe(s -> Log.e("join", s));
}




<div class="se-preview-section-delimiter"></div>

输出结果如下:

02-04 23:01:29.666 6763-6763/com.felix.testrxjava E/join: a0
02-04 23:01:30.664 6763-6763/com.felix.testrxjava E/join: b0
02-04 23:01:30.665 6763-6763/com.felix.testrxjava E/join: b1
02-04 23:01:30.665 6763-6763/com.felix.testrxjava E/join: a1
02-04 23:01:31.664 6763-6763/com.felix.testrxjava E/join: c1




<div class="se-preview-section-delimiter"></div>

10.4 combineLatest

RxJava的combineLatest()函数有点像zip()函数的特殊形式。正如我们已经学习的,zip()作用于最近未打包的两个Observables。相反,combineLatest()作用于最近发射的数据项:如果Observable1发射了A并且Observable2发射了B和C,combineLatest()将会分组处理AB和AC

我们和zip对比一下

public void combineLatest(View view) {
   Observable.combineLatest(Observable.interval(1000, TimeUnit.MILLISECONDS)
                   .map(key -> ((char) (97 + key)) + ""),
           interval(1500, TimeUnit.MILLISECONDS),
           (v1, v2) -> updateData(v1, v2))
           .take(8)
           .subscribe(x -> Log.e("combineLatest", x + ""));
}




<div class="se-preview-section-delimiter"></div>

输出结果为:

02-05 09:26:01.268 12433-14209/com.felix.testrxjava E/combineLatest: a0
02-05 09:26:01.767 12433-14208/com.felix.testrxjava E/combineLatest: b0
02-05 09:26:02.769 12433-14209/com.felix.testrxjava E/combineLatest: b1
02-05 09:26:02.769 12433-14209/com.felix.testrxjava E/combineLatest: c1
02-05 09:26:03.767 12433-14208/com.felix.testrxjava E/combineLatest: d1
02-05 09:26:04.268 12433-14209/com.felix.testrxjava E/combineLatest: d2
02-05 09:26:04.768 12433-14208/com.felix.testrxjava E/combineLatest: e2
02-05 09:26:05.768 12433-14209/com.felix.testrxjava E/combineLatest: e3




<div class="se-preview-section-delimiter"></div>

可以看出来,zip是木有重复的,而combineLatest合并是有重复的。这就是区别,前者是取的未打包的数据,后者是取的最近发射的数据(不管是否未打包)

10.5 switchOnNext

将一个发射多个Observables的Observable转换成另一个单独的Observable,后者发射那些Observables最近发射的数据项

switchOnNext订阅一个发射多个Observables的Observable。它每次观察那些Observables中的一个,Switch返回的这个Observable取消订阅前一个发射数据的Observable,开始发射最近的Observable发射的数据。注意:当原始Observable发射了一个新的Observable时(不是这个新的Observable发射了一条数据时),它将取消订阅之前的那个Observable。这意味着,在后来那个Observable产生之后到它开始发射数据之前的这段时间里,前一个Observable发射的数据将被丢弃。

 public void switchOnNext(View view) {
   Observable.switchOnNext(Observable.create(subscriber -> {
       for (int i = 0; i < 3; i++) {
           //每2s调用一次创建一个新的Observable
           subscriber.onNext(createswitchOnNextObservable(i));
           SystemClock.sleep(2000);
       }
   })).observeOn(AndroidSchedulers.mainThread())
           .cast(String.class)
           .subscribe(x -> Log.e("switchOnNext", x));
}

private Observable<String> createswitchOnNextObservable(int index) {
   return Observable.create(subscriber -> {
       for (int i = 0; i < 4; i++) {
           //每个内部Observable 都是1s发射一次数据
           subscriber.onNext("index " + index + " loop " + i);
           SystemClock.sleep(1000);
       }
   }).cast(String.class)
           .subscribeOn(Schedulers.newThread());
}




<div class="se-preview-section-delimiter"></div>

分析结果可以得出,第二个Observable开始发射数据的时候,第一个未接收的数据被遗弃了。

02-05 10:03:14.290 10116-10116/com.felix.testrxjava E/switchOnNext: index 0 loop 0
02-05 10:03:14.290 10116-10116/com.felix.testrxjava E/switchOnNext: index 0 loop 1
02-05 10:03:14.290 10116-10116/com.felix.testrxjava E/switchOnNext: index 1 loop 0
02-05 10:03:14.290 10116-10116/com.felix.testrxjava E/switchOnNext: index 1 loop 1
02-05 10:03:14.290 10116-10116/com.felix.testrxjava E/switchOnNext: index 2 loop 0
02-05 10:03:14.290 10116-10116/com.felix.testrxjava E/switchOnNext: index 2 loop 1
02-05 10:03:14.292 10116-10116/com.felix.testrxjava E/switchOnNext: index 2 loop 2
02-05 10:03:15.293 10116-10116/com.felix.testrxjava E/switchOnNext: index 2 loop 3




<div class="se-preview-section-delimiter"></div>

10.6 StartWith

如果你想要一个Observable在发射数据之前先发射一个指定的数据序列,可以使用StartWith操作符。(如果你想一个Observable发射的数据末尾追加一个数据序列可以使用Concat操作符。)

public void startWith(View view) {
   Observable.just(5, 6, 7)
           .startWith(Observable.just(1, 2, 3))
           .subscribe(x -> Log.e("startWith", x + ""));
}




<div class="se-preview-section-delimiter"></div>

输出如下,嵌套在前面

02-05 10:09:02.678 16388-16388/com.felix.testrxjava E/startWith: 1
02-05 10:09:02.678 16388-16388/com.felix.testrxjava E/startWith: 2
02-05 10:09:02.678 16388-16388/com.felix.testrxjava E/startWith: 3
02-05 10:09:02.679 16388-16388/com.felix.testrxjava E/startWith: 5
02-05 10:09:02.679 16388-16388/com.felix.testrxjava E/startWith: 6
02-05 10:09:02.679 16388-16388/com.felix.testrxjava E/startWith: 7




<div class="se-preview-section-delimiter"></div>

10.7 And/Then/When

使用Pattern和Plan作为中介,将两个或多个Observable发射的数据集合并到一起.

And/Then/When操作符组合的行为类似于zip,但是它们使用一个中间数据结构。接受两个或多个Observable,一次一个将它们的发射物合并到Pattern对象,然后操作那个Pattern对象,变换为一个Plan。随后将这些Plan变换为Observable的发射物。详细见rxjava-joins模块。

11 错误处理

很多操作符可用于对Observable发射的onError通知做出响应或者从错误中恢复.

java的异常分为错误(error)和异常(exception)两种,它们都是继承于Throwable类。

错误(error)一般是比较严重的系统问题,比如我们经常遇到的OutOfMemoryError、StackOverflowError等都是错误。错误一般继承于Error类,而Error类又继承于Throwable类,如果需要捕获错误,需要使用try..catch(Error e)或者try..catch(Throwable e)句式。使用try..catch(Exception e)句式无法捕获错误

异常(Exception)也是继承于Throwable类,一般是根据实际处理业务抛出的异常,分为运行时异常(RuntimeException)和普通异常。普通异常直接继承于Exception类,如果方法内部没有通过try..catch句式进行处理,必须通过throws关键字把异常抛出外部进行处理(即checked异常);而运行时异常继承于RuntimeException类,如果方法内部没有通过try..catch句式进行处理,不需要显式通过throws关键字抛出外部,如IndexOutOfBoundsException、NullPointerException、ClassCastException等都是运行时异常,当然RuntimeException也是继承于Exception类,因此是可以通过try..catch(Exception e)句式进行捕获处理的。

11.1 onErrorResumeNext

onErrorReturn操作符是在Observable发生错误或异常的时候(即将回调oError方法时),拦截错误并执行指定的逻辑,返回一个跟源Observable相同类型的结果,最后回调订阅者的onComplete方法

public void onErrorResumeNext(View view) {
   Observable.error(new Exception("error"))
           .onErrorResumeNext(Observable.just("a", "b", "c")).cast(String.class)
           .subscribe(x -> Log.e("onErrorResumeNext(Obs)", x),
                   error -> Log.e("onErrorResumeNext(Obs)", error.getMessage()),
                   () -> Log.e("onErrorResumeNext(Obs)", "onCompleted"));

   Observable.error(new Exception("error"))
           .onErrorResumeNext(throwable -> {
               return Observable.just(throwable.getMessage(), "d", "e");
           }).cast(String.class)
           .subscribe(x -> Log.e("onErrorResumeNext(Func)", x),
                   error -> Log.e("onErrorResumeNext(Func)", error.getMessage()),
                   () -> Log.e("onErrorResumeNext(Func)", "onCompleted"));
}




<div class="se-preview-section-delimiter"></div>

输出如下,我们可以发现,不仅调用了OnError,而且还调用了onCompleted,下同:

02-06 17:24:29.370 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Obs): a
02-06 17:24:29.370 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Obs): b
02-06 17:24:29.370 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Obs): c
02-06 17:24:29.370 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Obs): onCompleted
02-06 17:24:29.371 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Func): error
02-06 17:24:29.371 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Func): d
02-06 17:24:29.371 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Func): e
02-06 17:24:29.371 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Func): onCompleted




<div class="se-preview-section-delimiter"></div>

11.2 onErrorReturn

指示Observable在遇到错误时发射一个特定的数据,和onErrorResumeNext的区别是onErrorReturn的回调Func1返回的是一个值,而onErrorResumeNext返回的是一个Observable。

public void onErrorReturn(View view) {
   Observable.error(new Exception("error"))
           .onErrorReturn(throwable -> {
               return throwable.getMessage();
           }).cast(String.class)
           .subscribe(x -> Log.e("onErrorReturn", x),
                   error -> Log.e("onErrorReturn", error.getMessage()),
                   () -> Log.e("onErrorReturn", "onCompleted"));
}




<div class="se-preview-section-delimiter"></div>

输出如下:

02-06 17:25:32.773 3541-3541/com.felix.testrxjava E/onErrorReturn: error
02-06 17:25:32.773 3541-3541/com.felix.testrxjava E/onErrorReturn: onCompleted




<div class="se-preview-section-delimiter"></div>

11.3 onExceptionResumeNext

指示Observable遇到错误时继续发射数据.

onExceptionResumeNext操作符和onErrorResumeNext操作符类似,不同的地方在于onErrorResumeNext操作符是当Observable发生错误或异常时触发,而onExceptionResumeNext是当Observable发生异常时才触发。

public void onExceptionResumeNext(View view) {
   Observable.create(subscriber -> {
       for (int i = 0; i < 10; i++) {
           if (i == 5) {
               subscriber.onError(new Exception("error"));
           } else {
               subscriber.onNext("is " + i);
           }
       }
       subscriber.onCompleted();
   }).onErrorReturn(throwable -> throwable.getMessage())
           .cast(String.class)
           .subscribe(x -> Log.e("onExceptionResumeNext", x),
                   error -> Log.e("onExceptionResumeNext", error.getMessage()),
                   () -> Log.e("onExceptionResumeNext", "onCompleted"));

}




<div class="se-preview-section-delimiter"></div>

输出结果:

02-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: is 0
02-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: is 1
02-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: is 2
02-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: is 3
02-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: is 4
02-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: error
02-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: onCompleted




<div class="se-preview-section-delimiter"></div>

11.4 retry

retry操作符是当Observable发生错误或者异常时,重新尝试执行Observable的逻辑,如果经过n次重新尝试执行后仍然出现错误或者异常,则最后回调执行onError方法;当然如果源Observable没有错误或者异常出现,则按照正常流程执行。

 int index = 0;
public void retry(View view) {
   Observable.create(subscriber -> {
       index++;
       subscriber.onNext("index    "+index);
       subscriber.onError(new Exception("error index " + index));
   }).retry().cast(String.class)
           .subscribe(x -> Log.e("retry", x),
                   error -> Log.e("retry", error.getMessage()),




<div class="se-preview-section-delimiter"></div>

默认的retry()会一直重试直到成功,也可以传一个整型值给retry来指定重试次数。

也可以传递一个Func2函数给retry,通过函数规则来判断是否需要重试。

11.5 retryWhen

retryWhen操作符类似于retry操作符,都是在源observable出现错误或者异常时,重新尝试执行源observable的逻辑,不同在于retryWhen操作符是在源Observable出现错误或者异常时,通过回调第二个Observable来判断是否重新尝试执行源Observable的逻辑,如果第二个Observable没有错误或者异常出现,则就会重新尝试执行源Observable的逻辑,否则就会直接回调执行订阅者的onError方法。

retryWhen的参数是一个Func1,通过Func1的返回的Observable来决定如何重试。如果这个Observable发射了一项数据,它就重新订阅,如果这个Observable发射的是onError通知,它就将这个通知传递给观察者然后终止。

摘录来自: mcxiaoke. “ReactiveX文档中文翻译”。 iBooks.

public void retryWhen(View view) {
   Observable.create(subscriber -> {
       index++;
       subscriber.onNext("index    " + index);
       subscriber.onError(new Exception("error index " + index));
   }).retryWhen(observable -> {
       return Observable.interval(3, TimeUnit.SECONDS);
   }).cast(String.class)
           .subscribe(x -> Log.e("retryWhen", x),
                   error -> Log.e("retryWhen", error.getMessage()),
                   () -> Log.e("retryWhen", "onCompleted"));
}




<div class="se-preview-section-delimiter"></div>

这个将按规则,没3s重试一次

02-08 11:42:41.600 11208-11208/com.felix.testrxjava E/retryWhen: index    1
02-08 11:42:44.601 11208-11582/com.felix.testrxjava E/retryWhen: index    2
02-08 11:42:47.599 11208-11582/com.felix.testrxjava E/retryWhen: index    3
...




<div class="se-preview-section-delimiter"></div>

注意:retry/retryWhen操作符默认在trampoline调度器上执行。

12 辅助操作符

12.1 delay/delaySubscription

delay操作符让原始Observable在发射每项数据之前都暂停一段指定的时间段。效果是Observable发射的数据项在时间上向前整体平移了一个增量。

注意:delay不会平移onError通知,它会立即将这个通知传递给订阅者,同时丢弃任何待发射的onNext通知。然而它会平移一个onCompleted通知。

第一种 delay接受一个定义时长的参数(包括数量和单位)。每当原始Observable发射一项数据,delay就启动一个定时器,当定时器过了给定的时间段时,delay返回的Observable发射相同的数据项,这种delay默认在computation调度器上执行

Observable.create(subscriber -> {
       for (int i = 0; i < 3; i++) {
           subscriber.onNext("index" + i);
       }
       if (new Random().nextBoolean()) {
           subscriber.onError(new Exception("error"));
       }else {
           subscriber.onCompleted();
       }
   }).delay(2, TimeUnit.SECONDS).cast(String.class)
           .subscribe(str -> Log.e("delay", str),
                   throwable ->Log.e("delay", throwable.getMessage()),
                   ()->Log.e("delay", "onCompleted"));




<div class="se-preview-section-delimiter"></div>

因为加了随机函数,点击了三次,打印结果如下:

02-13 22:48:37.735 13059-13715/com.felix.testrxjava E/delay: index0
02-13 22:48:37.735 13059-13715/com.felix.testrxjava E/delay: index1
02-13 22:48:37.735 13059-13715/com.felix.testrxjava E/delay: index2
02-13 22:48:37.735 13059-13715/com.felix.testrxjava E/delay: onCompleted

02-13 22:48:39.034 13059-13349/com.felix.testrxjava E/delay: --error--

02-13 22:48:42.322 13059-13368/com.felix.testrxjava E/delay: --error--




<div class="se-preview-section-delimiter"></div>

第二种delay不是用常数参数,而是使用一个函数 Func1 针对原始Observable的每一项数据返回一个Observable,它监视返回的这个Observable,当任何那样的Observable终止时,delay返回的Observable就发射关联的那项数据。这种delay默认不在任何特定的调度器上执行

 Observable.just("a", "b", "c")
                .delay(index -> {
                    return Observable.just(index).delay(x++, TimeUnit.SECONDS);
                }).subscribe(str -> Log.e("delay2", str),
                throwable -> Log.e("delay2", throwable.getMessage()),
                () -> Log.e("delay2", "onCompleted"));  




<div class="se-preview-section-delimiter"></div>

返回结果如下

02-13 23:19:39.189 27635-27917/com.felix.testrxjava E/delay2: a
02-13 23:19:40.190 27635-27918/com.felix.testrxjava E/delay2: b
02-13 23:19:41.190 27635-27919/com.felix.testrxjava E/delay2: c
02-13 23:19:41.190 27635-27919/com.felix.testrxjava E/delay2: onCompleted




<div class="se-preview-section-delimiter"></div>

第三种delay对每一项数据使用一个Observable作为原始Observable的延时定时器。这种delay默认不在任何特定的调度器上执行。

12.2 Materialize/Dematerialize

Materialize将数据项和事件通知都当做数据项发射,Dematerialize刚好相反。

materialize将来自原始Observable的通知转换为Notification对象,然后它返回的Observable会发射这些数据;dematerialize反转这个过程,将原始Observable发射的Notification对象还原成Observable的通知。

12.3 serialize

强制一个Observable连续调用并保证行为正确。主要用于多线程调用的时候,保证rxjava的正确性。

12.4 timeout

  1. timeout(long,TimeUnit))

每当原始Observable发射了一项数据,timeout就启动一个计时器,如果计时器超过了指定指定的时长而原始Observable没有发射另一项数据,timeout就抛出TimeoutException,以一个错误通知终止Observable。它默认在computation调度器上执行。

  1. timeout(long,TimeUnit,Observable))

在超时时会切换到使用一个你指定的备用的Observable,而不是发错误通知。它也默认在computation调度器上执行。

  1. timeout(Func1))

使用一个函数针对原始Observable的每一项返回一个Observable,如果当这个Observable终止时原始Observable还没有发射另一项数据,就会认为是超时了,timeout就抛出TimeoutException,以一个错误通知终止Observable。这个timeout默认在immediate调度器上执行。

  1. timeout(Func1,Observable))

同时指定超时时长和备用的Observable。它默认在immediate调度器上执行。

  1. timeout(Func0,Func1))

除了给每一项设置超时,还可以单独给第一项设置一个超时。它默认在immediate调度器上执行。

12.5 timestamp

将一个发射T类型数据的Observable转换为一个发射类型为Timestamped的数据的Observable,每一项都包含数据的原始发射时间。timestamp默认在immediate调度器上执行.

public void timestamp(View view) {
    Observable.interval(1000, TimeUnit.MILLISECONDS)
            .take(4)
            .timestamp()
            .subscribe(ts -> LogUtils.e(ts.getTimestampMillis() + "--" + ts.getValue()));
    }
}




<div class="se-preview-section-delimiter"></div>

将结果转换了,增加了一个时间戳标志。

02-18 00:53:00.181 19330-19555/com.felix.testrxjava E/LogUtils: 1487350380181--0
02-18 00:53:01.181 19330-19555/com.felix.testrxjava E/LogUtils: 1487350381181--1
02-18 00:53:02.181 19330-19555/com.felix.testrxjava E/LogUtils: 1487350382180--2
02-18 00:53:03.181 19330-19555/com.felix.testrxjava E/LogUtils: 1487350383180--3




<div class="se-preview-section-delimiter"></div>

13 do

注册一个动作作为原始Observable生命周期事件的一种占位符,你可以注册回调,当Observable的某个事件发生时,Rx会在与Observable链关联的正常通知集合中调用它。

13.1 doOnEach

doOnEach操作符让你可以注册一个回调,它产生的Observable每发射一项数据就会调用它一次。也就是onNext,onError,onCompleted三个回调都会触发doOnEach回调其响应的方法。你可以以Action的形式传递参数给它,这个Action接受一个onNext的变体Notification作为它的唯一参数,你也可以传递一个Observable给doOnEach,这个Observable的onNext会被调用,就好像它订阅了原始的Observable一样。

 Observable.just(1, 2, 3)
        .doOnEach(notification -> {
            Log.e("---", notification.getKind() + " --" + notification.getValue()
                    + "_" + notification.isOnNext() + "_" + notification.isOnCompleted());
        })
        .subscribe(str -> Log.e("doOnEach", str + ""));




<div class="se-preview-section-delimiter"></div>

可以看出来Notification包含了当前Observable的各种状态,返回值如下:

02-14 21:13:29.058 25118-25118/com.felix.testrxjava E/---: OnNext --1_true_false
02-14 21:13:29.058 25118-25118/com.felix.testrxjava E/doOnEach: 1
02-14 21:13:29.058 25118-25118/com.felix.testrxjava E/---: OnNext --2_true_false
02-14 21:13:29.058 25118-25118/com.felix.testrxjava E/doOnEach: 2
02-14 21:13:29.058 25118-25118/com.felix.testrxjava E/---: OnNext --3_true_false
02-14 21:13:29.058 25118-25118/com.felix.testrxjava E/doOnEach: 3
02-14 21:13:29.058 25118-25118/com.felix.testrxjava E/---: OnCompleted --null_false_true




<div class="se-preview-section-delimiter"></div>

doOnEach还有一个实现方式

  Observable.just(11, 22, 33, 44)
        .doOnEach(new Observer<Integer>() {
            @Override
            public void onCompleted() {
                Log.e("doOnEach2--", "onCompleted");
            }
            @Override
            public void onError(Throwable e) {
                Log.e("doOnEach2--", "e  " + e.getMessage());
            }
            @Override
            public void onNext(Integer integer) {
                Log.e("doOnEach2--", "integer " + integer);
            }
        })
        .subscribe(str -> Log.e("doOnEach2", str + ""));




<div class="se-preview-section-delimiter"></div>

我们通过返回值看出来,回调了Observer的onNext方法。

02-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2--: onNext 11
02-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2: 11
02-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2--: onNext 22
02-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2: 22
02-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2--: onNext 33
02-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2: 33
02-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2--: onNext 44
02-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2: 44
02-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2--: onCompleted




<div class="se-preview-section-delimiter"></div>

13.2 doOnNext/doOnCompleted/doOnError

doOnNext操作符类似于doOnEach(Action1),但是它的Action不是接受一个Notification参数,而是接受发射的数据项。只有onNext回调的时候回触发doOnNext

 public void doOnNext(View view) {
    Observable.just(1, 2, 3)
            .doOnNext(integer -> Log.e("doOnNext", "doOnNext    " + integer))
            .subscribe(str -> Log.e("doOnNext", str + ""));
}




<div class="se-preview-section-delimiter"></div>

我们看看输出,会同时调用doOnNext 和订阅方法,且接收到的数据也是一样的

02-15 10:01:29.471 1975-1975/com.felix.testrxjava E/doOnNext: doOnNext    1
02-15 10:01:29.472 1975-1975/com.felix.testrxjava E/doOnNext: 1
02-15 10:01:29.472 1975-1975/com.felix.testrxjava E/doOnNext: doOnNext    2
02-15 10:01:29.472 1975-1975/com.felix.testrxjava E/doOnNext: 2
02-15 10:01:29.472 1975-1975/com.felix.testrxjava E/doOnNext: doOnNext    3
02-15 10:01:29.472 1975-1975/com.felix.testrxjava E/doOnNext: 3




<div class="se-preview-section-delimiter"></div>

doOnCompleted/doOnError和doOnNext类似,只有在相应的方法调用的时候才会调用此方法。

13.3 doOnSubscribe/doOnUnsubscribe

doOnSubscribe,当观察者订阅它生成的Observable它就会被调用。

doOnUnsubscribe,当观察者取消订阅它生成的Observable它就会被调用。

public void doOnSubscribe(View view) {
    Subscription subscription = Observable.just(1, 2, 3)
            .doOnSubscribe(() -> Log.e("doOnSubscribe", "Subscribe"))
            .doOnUnsubscribe(() -> Log.e("doOnUnsubscribe", "Unsubscribe"))
            .subscribe();

    if (!subscription.isUnsubscribed()) {
        subscription.unsubscribe();
    }
}




<div class="se-preview-section-delimiter"></div>

看一下输出结果

02-15 10:15:22.149 23724-23724/com.felix.testrxjava E/doOnSubscribe: Subscribe
02-15 10:15:22.149 23724-23724/com.felix.testrxjava E/doOnUnsubscribe: Unsubscribe




<div class="se-preview-section-delimiter"></div>

13.3 doOnTerminate/doAfterTerminate

doOnTerminate 操作符注册一个动作,当它产生的Observable终止之前会被调用,无论是正常还是异常终止。

doAfterTerminate 操作符注册一个动作,当它产生的Observable终止之后会被调用,无论是正常还是异常终止。

public void doOnTerminate(View view) {
    Observable.create(subscriber -> {
        if (new Random().nextBoolean()) {
            subscriber.onNext("aa");
            subscriber.onCompleted();
        }
        subscriber.onNext("bb");
        subscriber.onError(new Exception("bb error"));
    }).doOnTerminate(() -> Log.e("doOnTerminate", "OnTerminate"))
            .doAfterTerminate(() -> Log.e("doAfterTerminate", "AfterTerminate"))
            .cast(String.class)
            .subscribe(str -> Log.e("", str), e -> Log.e("", e.getMessage()));
}




<div class="se-preview-section-delimiter"></div>

可以看出来,因为用了随机函数,可能出现这两种中的一种。但不管成功还是失败,都是一个是在会调前调用,一个是在回调后调用。

02-15 10:29:41.935 14858-14858/com.felix.testrxjava E/doOnTerminate: OnTerminate
02-15 10:29:41.935 14858:14858 E/         bb error
02-15 10:29:41.935 14858-14858/com.felix.testrxjava E/doAfterTerminate: AfterTerminate


02-15 10:30:54.859 14858-14858/com.felix.testrxjava E/doAfterTerminate: AfterTerminate
02-15 10:31:01.661 14858-14858/com.felix.testrxjava E/doOnTerminate: OnTerminate
02-15 10:31:01.661 14858-14858/com.felix.testrxjava E/doAfterTerminate: AfterTerminate




<div class="se-preview-section-delimiter"></div>

14 BlockingObservable

使用 BlockingObservable 可以把 Observable 中的数据通过阻塞的方式发射出来。任何一个 Observable 都可以使用下面两种方式来转换为阻塞的 Observable。

BlockingObservable.from
Observable.toBlocking




<div class="se-preview-section-delimiter"></div>

14.1 getIterator

将observable转成数据结果iterator类型,然后可以按iterator来获取数据。是阻塞式的,当有observable发出时才会输出数据。

getIterator操作符只能用于BlockingObservable以及它的子类

public void getIterator(View view) {
    Iterator it = BlockingObservable.from(Observable.interval(1, TimeUnit.SECONDS).take(5))
            .getIterator();
    while (it.hasNext()) {
        LogUtils.e(it.next().toString());
    }
}




<div class="se-preview-section-delimiter"></div>

14.2 toList

将Observable转成数据类型list,阻塞式。通常,发射多项数据的Observable会为每一项数据调用onNext方法。你可以用toList操作符改变这个行为,让Observable将多项数据组合成一个List,然后调用一次onNext方法传递整个列表。

如果原始Observable没有发射任何数据就调用了onCompleted,toList返回的Observable会在调用onCompleted之前发射一个空列表。如果原始Observable调用了onError,toList返回的Observable会立即调用它的观察者的onError方法。

14.3 toSortedList

toSortedList类似于toList,不同的是,它会对产生的列表排序,默认是自然升序,如果发射的数据项没有实现Comparable接口,会抛出一个异常。然而,你也可以传递一个函数作为用于比较两个数据项,这是toSortedList不会使用Comparable接口。

14.2 toIterable

把 Observable 转换为 iterables ,阻塞式。然后可以传统的 Java 方式来遍历这些集合。当需要处理数据的时候,就调用 Iterator 的 next() 函数,如果有数据 next() 就直接返回;如果没有数据 next() 函数就阻塞直到有数据产生。

toIterable操作符只能用于BlockingObservable以及它的子类

14.3 toFuture

将Observable转换为一个返回单个数据项的Future,非阻塞式。如果原始Observable发射多个数据项,Future会收到一个IllegalArgumentException;如果原始Observable没有发射任何数据,Future会收到一个NoSuchElementException。如果你想将发射多个数据项的Observable转换为Future,可以这样用:myObservable.toList().toBlocking().toFuture()。

toFuture操作符只能用于BlockingObservable以及它的子类

14.4 toMap

toMap收集原始Observable发射的所有数据项到一个Map(默认是HashMap)然后发射这个Map。你可以提供一个用于生成Map的Key的函数,还可以提供一个函数转换数据项到Map存储的值(默认数据项本身就是值)

 public void toMap(View view) {
        Observable.just("a", "b", "c")
                .toMap(s -> s + "-", 
                            s -> s + "=",
                          ()->new HashMap<String, String>(3))
                .subscribe(LogUtils::e);
    }
}

public final static <K, V> void e(Map<K, V> maps) {
    for (Map.Entry entry : maps.entrySet()) {
        e("key:" + entry.getKey() + " value: " + entry.getValue());
    }
}




<div class="se-preview-section-delimiter"></div>

输出如下,可以看出来,第一个函数产生key,第二个参数产生value(无此参数则使用发射的值),第三个参数则是一个map工厂用于创建一个map以存储值。

02-19 23:03:06.583 15523-15523/com.felix.testrxjava E/LogUtils: c--- +++ c
02-19 23:03:06.583 15523-15523/com.felix.testrxjava E/LogUtils: a--- +++ a
02-19 23:03:06.583 15523-15523/com.felix.testrxjava E/LogUtils: b--- +++ b




<div class="se-preview-section-delimiter"></div>

14.5 toMultiMap

toMultiMap类似于toMap,不同的是,它生成的这个Map同时还是一个ArrayList(默认是这样,你可以传递一个可选的工厂方法修改这个行为)

14.6 nest

将一个Observable转换为一个发射这个Observable的Observable.

public void nest(View view) {
    Observable.just(1, 2, 3, 4, 5).nest()
            .subscribe(observable -> observable.subscribe(LogUtils::e));
}




<div class="se-preview-section-delimiter"></div>

打印结果如下:

02-19 23:02:07.954 15523-15523/com.felix.testrxjava E/LogUtils:  1
02-19 23:02:07.954 15523-15523/com.felix.testrxjava E/LogUtils:  2
02-19 23:02:07.954 15523-15523/com.felix.testrxjava E/LogUtils:  3
02-19 23:02:07.954 15523-15523/com.felix.testrxjava E/LogUtils:  4
02-19 23:02:07.954 15523-15523/com.felix.testrxjava E/LogUtils:  5




<div class="se-preview-section-delimiter"></div>

15 条件和布尔操作符

15.1 all

传递一个谓词函数给all操作符,这个函数接受原始Observable发射的数据,根据计算返回一个布尔值。All返回一个只发射一个单个布尔值的Observable,如果原始Observable正常终止并且每一项数据都满足条件,就返回true;如果原始项数据都满足条件,就返回true;如果原始Observable的任何一项数据不满足条件就返回False。

 Observable.just(5, 6, 7, 8, 9)
            .all(integer -> integer > 4)
            .subscribe(LogUtils::e);
}

public final static void e(boolean flag) {
        Log.e(TAG, flag ? "true" : "false");
    }




<div class="se-preview-section-delimiter"></div>

15.2 amb/ambWith

当你传递多个Observable给amb时,它只发射其中一个Observable的数据和通知:首先发送通知给amb的那个,不管发射的是一项数据还是一个onError或onCompleted通知。Amb将忽略和丢弃其它所有Observables的发射物。

public void amb(View view) {
    Observable.amb(Observable.create(subscriber -> {
                SystemClock.sleep(200);
                subscriber.onNext(1);
                subscriber.onCompleted();
            }).subscribeOn(Schedulers.newThread()),
            Observable.create(subscriber -> {
                SystemClock.sleep(100);
                subscriber.onError(new Exception("error"));
                subscriber.onCompleted();
            }).subscribeOn(Schedulers.newThread()))
            .cast(Integer.class).subscribe(LogUtils::e, LogUtils::e);
}




<div class="se-preview-section-delimiter"></div>

15.3 contains

给contains传一个指定的值,如果原始Observable发射了那个值,它返回的Observable将发射true,否则发射false。

public void contains(View view) {
    Observable.create(subscriber -> {
        for (int i = 0; i < 5; i++) {
            subscriber.onNext(i);
            SystemClock.sleep(200);
        }
    }).contains(3)
            .subscribe(LogUtils::e);
}




<div class="se-preview-section-delimiter"></div>

15.4 exists

通过一个谓词函数测试原始Observable发射的数据,只要任何一项满足条件就返回一个发射true的Observable,否则返回一个发射false的Observable。

15.5 isEmpty

用于判定原始Observable是否没有发射任何数据。

 public void isEmpty(View view) {
    Observable.empty().isEmpty().subscribe(LogUtils::e);
    Observable.just(12, 3).isEmpty().subscribe(LogUtils::e);
    Observable.error(new Exception("error")).isEmpty().subscribe(LogUtils::e, LogUtils::e);
}




<div class="se-preview-section-delimiter"></div>

从下面输出可以看出来,如果原Observable抛出一个异常,则会直接调用onError,而不会走isEmpty方法

02-20 08:28:49.236 29580-29580/com.felix.testrxjava E/LogUtils: true
02-20 08:28:49.237 29580-29580/com.felix.testrxjava E/LogUtils: false
02-20 08:28:49.238 29580-29580/com.felix.testrxjava E/LogUtils: throwable: error

15.6 defaultIfEmpty

defaultIfEmpty简单的精确地发射原始Observable的值,如果原始Observable没有发射任何数据正常终止(以onCompleted的形式),defaultIfEmpty返回的Observable就发射一个你提供的默认值。

15.7 sequenceEqual

传递两个Observable给SequenceEqual操作符,它会比较两个Observable的发射物,如果两个序列是相同的(相同的数据,相同的顺序,相同的终止状态),它就发射true,否则发射false。第三个参数,可以传递一个函数用于比较两个数据项是否相同.

15.8 skipUntil

skipUntil订阅原始的Observable,但是忽略它的发射物,直到第二个Observable发射了一项数据那一刻,它开始发射原始Observable。

15.9 skipWhile

skipWhile订阅原始的Observable,但是忽略它的发射物,直到你指定的某个条件变为false的那一刻,它开始发射原始Observable。

15.10 takeUntil

takeUntil订阅并开始发射原始Observable,它还监视你提供的第二个Observable。如果第二个Observable发射了一项数据或者发射了一个终止通知,takeUntil返回的Observable会停止发射原始Observable并终止。第二个Observable发射一项数据或一个onError通知或一个onCompleted通知都会导致takeUntil停止发射数据。

还有一个版本的takeUntil,不在RxJava 1.0.0版中,它使用一个谓词函数而不是第二个Observable来判定是否需要终止发射数据,它的行为类似于takeWhile。

15.11 takeWhile

takeWhile操作符返回一个镜像原始Observable行为的Observable,直到某一项数据你指定的函数返回false那一刻,这个新的Observable发射onCompleted终止通知。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值