Continue to the previous article: Detailed explanation and examples of auxiliary operation of Rxjava2 Observable (1)
8. TimeInterval
Convert the Observable of the transmitted data to the Observable of the transmitted time interval.
The TimeInterval operator intercepts the data items emitted by the original Observable and replaces them with objects that emit the time interval between adjacent emitters.
This operator converts the original Observable to another Observable, and the latter sends a flag to replace the data item of the former, which represents the length of time passed between two consecutive emitters of the former. The first emitter of the new Observable represents the length of time that elapses between the time the observer subscribes to the original Observable and the time the original Observable launches its first data. There is no emitter corresponding to the time between the original Observable transmitting the last data and transmitting the onCompleted notification.
Example code:
/** * 1. timeInterval(Scheduler scheduler) * scheduler: Optional parameter, specify scheduling thread * Receive the original data item, and launch the object representing the time interval between adjacent emitters */ Observable.intervalRange(1, 10, 100, 100, TimeUnit.MILLISECONDS) .timeInterval() // . timeInterval(Schedulers.newThread()) / / specifies the worker thread .subscribe(new Observer<Timed<Long>>() { @Override public void onSubscribe(Disposable d) { System.out.println("--> onSubscribe(1)"); } @Override public void onNext(Timed<Long> longTimed) { long time = longTimed.time(); // Interval between consecutive data TimeUnit unit = longTimed.unit(); // Time interval unit between consecutive data Long value = longTimed.value(); // Data item sent by Observable System.out.println("--> onNext(1): " + longTimed.toString()); } @Override public void onError(Throwable e) { System.out.println("--> onError(1): " + e); } @Override public void onComplete() { System.out.println("--> onComplete(1)"); } }); System.in.read(); System.out.println("-------------------------------------------------"); /** * 2. timeInterval(TimeUnit unit, Scheduler scheduler) * Specify the time interval unit and the specified working thread, receive the original data item, and launch the object representing the time interval of adjacent emitters */ Observable.intervalRange(1, 10, 1000, 1200, TimeUnit.MILLISECONDS) // . timeInterval(TimeUnit.SECONDS) / / specify the time interval unit .timeInterval(TimeUnit.SECONDS, Schedulers.newThread()) // Specify interval units and worker threads .subscribe(new Observer<Timed<Long>>() { @Override public void onSubscribe(Disposable d) { System.out.println("--> onSubscribe(2)"); } @Override public void onNext(Timed<Long> longTimed) { System.out.println("--> onNext(2): " + longTimed.toString()); } @Override public void onError(Throwable e) { System.out.println("--> onError(2): " + e); } @Override public void onComplete() { System.out.println("--> onComplete(2)"); } }); System.in.read();
Output:
--> onSubscribe(1) --> onNext(1): Timed[time=104, unit=MILLISECONDS, value=1] --> onNext(1): Timed[time=100, unit=MILLISECONDS, value=2] --> onNext(1): Timed[time=100, unit=MILLISECONDS, value=3] --> onNext(1): Timed[time=100, unit=MILLISECONDS, value=4] --> onNext(1): Timed[time=100, unit=MILLISECONDS, value=5] --> onNext(1): Timed[time=100, unit=MILLISECONDS, value=6] --> onNext(1): Timed[time=100, unit=MILLISECONDS, value=7] --> onNext(1): Timed[time=100, unit=MILLISECONDS, value=8] --> onNext(1): Timed[time=100, unit=MILLISECONDS, value=9] --> onNext(1): Timed[time=100, unit=MILLISECONDS, value=10] --> onComplete(1) ------------------------------------------------- --> onSubscribe(2) --> onNext(2): Timed[time=1, unit=SECONDS, value=1] --> onNext(2): Timed[time=1, unit=SECONDS, value=2] --> onNext(2): Timed[time=1, unit=SECONDS, value=3] --> onNext(2): Timed[time=1, unit=SECONDS, value=4] --> onNext(2): Timed[time=1, unit=SECONDS, value=5] --> onNext(2): Timed[time=2, unit=SECONDS, value=6] --> onNext(2): Timed[time=1, unit=SECONDS, value=7] --> onNext(2): Timed[time=1, unit=SECONDS, value=8] --> onNext(2): Timed[time=1, unit=SECONDS, value=9] --> onNext(2): Timed[time=1, unit=SECONDS, value=10] --> onComplete(2)
Javadoc: timeInterval()
Javadoc: timeInterval(Scheduler scheduler)
Javadoc: timeInterval(TimeUnit unit)
Javadoc: timeInterval(TimeUnit unit, Scheduler scheduler)
9. Timeout
For an image of the original Observable, if no data is transmitted after a specified time, it will send an error notification.
The implementation in RxJava is the timeout operator with several different variations.
9.1 timeout(timeout, timeUnit)
If the original Observable does not transmit any data after a specified period of time, the Timeout operator will terminate the Observable with an onError notification.
Example code:
/** * 1. timeout(long timeout, TimeUnit timeUnit) * Accept a time parameter. If no data item is sent within the specified time period, an Error notification will be sent, * Or whenever the original Observable sends a piece of data, the timeout starts a timer, * If the timer exceeds the specified time and the original Observable does not transmit another data, * TimeoutException is thrown to terminate Observable with an error notification. */ Observable.create(new ObservableOnSubscribe<Long>() { @Override public void subscribe(ObservableEmitter<Long> emitter) throws Exception { // Thread.sleep(2000); / / after a delay of 2 seconds, the data will be transmitted, and a TimeoutException will appear emitter.onNext(1L); Thread.sleep(2000); // Data will be sent after 2 seconds delay, and TimeoutException will appear emitter.onNext(2L); emitter.onComplete(); } }).timeout(1, TimeUnit.SECONDS) // Specify a timeout period of 1 second .subscribe(new Observer<Long>() { @Override public void onSubscribe(Disposable d) { System.out.println("--> onSubscribe(1)"); } @Override public void onNext(Long aLong) { System.out.println("--> onNext(1): " + aLong); } @Override public void onError(Throwable e) { System.out.println("--> onError(1): " + e); } @Override public void onComplete() { System.out.println("--> onComplete(1)"); } }); System.in.read();
Output:
--> onSubscribe(1) --> onNext(1): 1 --> onError(1): java.util.concurrent.TimeoutException: The source did not signal an event for 1 seconds and has been terminated.
9.2 timeout(timeout, timeUnit, scheduler, other)
After the specified time period, the timeout will switch to use a standby Observable specified by you instead of sending an onError notification. You can specify the worker thread through the scheduler.
Example code:
/** * 2. timeout(long timeout, TimeUnit timeUnit, * Scheduler scheduler, // Optional parameter, specify thread scheduler * ObservableSource other // Optional parameter, timeout standby Observable * ) * * After the specified time period, timeout will switch to use a standby Observable specified by you instead of sending an onError notification. */ Observable.create(new ObservableOnSubscribe<Long>() { @Override public void subscribe(ObservableEmitter<Long> emitter) throws Exception { // Thread.sleep(2000); / / after a delay of 2 seconds, the data will be transmitted, and a TimeoutException will appear emitter.onNext(1L); Thread.sleep(2000); // Data will be sent after 2 seconds delay, and TimeoutException will appear emitter.onNext(2L); emitter.onComplete(); } }).timeout(1, TimeUnit.SECONDS, // Specify a timeout period of 1 second Schedulers.newThread(), // Specify worker as child Observable.just(888L)) // Observable launched by default after timeout .subscribe(new Observer<Long>() { @Override public void onSubscribe(Disposable d) { System.out.println("--> onSubscribe(2)"); } @Override public void onNext(Long aLong) { System.out.println("--> onNext(2): " + aLong); } @Override public void onError(Throwable e) { System.out.println("--> onError(2): " + e); } @Override public void onComplete() { System.out.println("--> onComplete(2)"); } }); System.in.read();
Output:
--> onSubscribe(2) --> onNext(2): 1 --> onNext(2): 888 --> onComplete(2)
Javadoc: timeout(long timeout, TimeUnit timeUnit, Scheduler scheduler, ObservableSource other)
9.3 timeout(Function itemTimeoutIndicator, ObservableSource other)
Use a function itemTimeoutIndicator to return an Observable for each item of the original Observable. If the original Observable has not yet transmitted another item of data when the Observable is terminated, it will be considered as a timeout. If there is no other specified for timeout standby, it will throw TimeoutException to terminate bserveable with an error notification. Otherwise, it will be transmitted after timeout Standby Observable.
Example code:
/** * 3. timeout(Function<T, ObservableSource> itemTimeoutIndicator * ObservableSource other // Optional parameter, standby Observable transmitted after timeout * ) * Return an Observable for each item of the original Observable, * If the original Observable does not transmit another data when this Observable terminates, it will be considered as timeout, * If no timeout standby Observable is specified, a TimeoutException is thrown to terminate the Observable with an error notification, * Otherwise, the standby Observable will be launched after timeout. */ Observable.create(new ObservableOnSubscribe<Long>() { @Override public void subscribe(ObservableEmitter<Long> emitter) throws Exception { emitter.onNext(1L); Thread.sleep(3000); // After a delay of 3 seconds, the data will be transmitted, and there will be a TimeoutException emitter.onNext(2L); emitter.onComplete(); } }).timeout(new Function<Long, ObservableSource<Long>>() { @Override public ObservableSource<Long> apply(Long aLong) throws Exception { // One Observable is sent for each raw data to indicate the Timeout of the next data transmission. Here, the 1 second Timeout is specified return Observable.timer(1, TimeUnit.SECONDS); } }, Observable.just(888L)) // Observable launched by default after timeout .subscribe(new Observer<Long>() { @Override public void onSubscribe(Disposable d) { System.out.println("--> onSubscribe(3)"); } @Override public void onNext(Long aLong) { System.out.println("--> onNext(3): " + aLong); } @Override public void onError(Throwable e) { System.out.println("--> onError(3): " + e); } @Override public void onComplete() { System.out.println("--> onComplete(3)"); } }); System.in.read();
Output:
--> onSubscribe(3) --> onNext(3): 1 --> onNext(3): 888 --> onComplete(3)
Javadoc: timeout(Function<T, ObservableSource> itemTimeoutIndicator)
Javadoc: timeout(Function<T, ObservableSource> itemTimeoutIndicator, ObservableSource other)
10. Timestamp
Attach a specified timestamp to the data item emitted by Observable.
timestamp, which converts an Observable transmitting time type data into an Observable transmitting time type data. Each item contains the original transmitting time information and the original data.
Example code:
/** * 1. timestamp(Scheduler scheduler) * scheduler: Optional parameter, specify thread scheduler * * Attach a time stamp to the data item emitted by Observable */ Observable.intervalRange(1, 5, 1, 100, TimeUnit.MILLISECONDS) .timestamp(Schedulers.newThread()) // Specifies that processing is scheduled on a child thread .subscribe(new Observer<Timed<Long>>() { @Override public void onSubscribe(Disposable d) { System.out.println("--> onSubscribe(1)"); } @Override public void onNext(Timed<Long> longTimed) { long time = longTimed.time(); // Interval between consecutive data TimeUnit unit = longTimed.unit(); // Time interval unit between consecutive data Long value = longTimed.value(); // Data item sent by Observable System.out.println("--> onNext(1): " + longTimed); } @Override public void onError(Throwable e) { System.out.println("--> onError(1): " + e); } @Override public void onComplete() { System.out.println("--> onComplete(1)"); } }); System.in.read(); System.out.println("-------------------------------------------"); /** * 2. timestamp(TimeUnit unit, Scheduler scheduler) * scheduler: Optional parameter, specify thread scheduler * * Attach a time stamp information of the specified unit to the data item emitted by Observable */ Observable.intervalRange(1, 5, 1, 1200, TimeUnit.MILLISECONDS) .timestamp(TimeUnit.SECONDS, Schedulers.newThread()) // Specify the time unit as seconds, and schedule the processing in the sub thread .subscribe(new Observer<Timed<Long>>() { @Override public void onSubscribe(Disposable d) { System.out.println("--> onSubscribe(2)"); } @Override public void onNext(Timed<Long> longTimed) { System.out.println("--> onNext(2): " + longTimed); } @Override public void onError(Throwable e) { System.out.println("--> onError(2): " + e); } @Override public void onComplete() { System.out.println("--> onComplete(2)"); } }); System.in.read();
Output:
--> onSubscribe(1) --> onNext(1): Timed[time=1577455367446, unit=MILLISECONDS, value=1] --> onNext(1): Timed[time=1577455367545, unit=MILLISECONDS, value=2] --> onNext(1): Timed[time=1577455367645, unit=MILLISECONDS, value=3] --> onNext(1): Timed[time=1577455367745, unit=MILLISECONDS, value=4] --> onNext(1): Timed[time=1577455367845, unit=MILLISECONDS, value=5] --> onComplete(1) ------------------------------------------- --> onSubscribe(2) --> onNext(2): Timed[time=1577455369, unit=SECONDS, value=1] --> onNext(2): Timed[time=1577455370, unit=SECONDS, value=2] --> onNext(2): Timed[time=1577455371, unit=SECONDS, value=3] --> onNext(2): Timed[time=1577455373, unit=SECONDS, value=4] --> onNext(2): Timed[time=1577455374, unit=SECONDS, value=5] --> onComplete(2)
Javadoc: timestamp()
Javadoc: timestamp(Scheduler scheduler)
Javadoc: timestamp(TimeUnit unit)
Javadoc: timestamp(TimeUnit unit, Scheduler scheduler)
11. Using
Create a one-time resource that exists only in the Observable lifecycle.
The Using operator allows you to instruct Observable to create a resource that only exists in its life cycle. When the Observable terminates, the resource will be released automatically.
The using operator takes three parameters:
- observableFactory: a factory function for users to create one-time assets
- resourceFactory: a factory function for creating Observable
- disposeFunction: a function used to release resources
When an observer subscribes to the Observable returned by using, using will use the Observable factory function to create the Observable to be observed by the observer, and use the resource factory function to create a resource you want to create. When the observer unsubscribes from the Observable, or when the observer terminates (either normally or by mistake), using uses a third function to release the resources it creates.
Example code:
/** * For resource objects that exist in the lifecycle of Observable */ class MyResource { private String resource; public MyResource(String resource) { this.resource = resource; } @Override public String toString() { return "MyResource{" + "resource='" + resource + '\'' + '}'; } public void releaseResource() { System.out.println("----> MyResource resource is release. "); resource = null; } } /** * 1. using(Callable resourceSupplier, Function sourceSupplier, Consumer disposer, boolean eager) * * resourceSupplier: // A factory function for users to create one-time resources * sourceSupplier: // A factory function for creating Observable * disposer: // A function for releasing resources * eager: // Optional parameter. If it is true, the processing of the third function, disposer, is executed before the end of Observable * * When an observer subscribes to the Observable returned by using, using will use the Observable factory function to create the Observable to be observed by the observer, * Also use the resource factory function to create a resource you want to create. * When the observer unsubscribes from the Observable, or when the observer terminates (either normally or by mistake), * using Use the third function to release the resources it creates. */ Observable.using( // A factory function for users to create one-time resources new Callable<MyResource>() { @Override public MyResource call() throws Exception { System.out.println("----> resourceSupplier call"); return new MyResource("This is Observable resource!"); } }, // A factory function for creating Observable. The Observable returned by this function is the Observable finally observed new Function<MyResource, ObservableSource<Long>>() { @Override public ObservableSource<Long> apply(MyResource myResource) throws Exception { System.out.println("----> sourceSupplier apply: " + myResource); return Observable.rangeLong(1, 5); } }, // A function for releasing resources new Consumer<MyResource>() { @Override public void accept(MyResource myResource) throws Exception { System.out.println("----> disposer accept: "); myResource.releaseResource(); } }, // Optional parameter. If it is true, the function to release resources will be executed before the end of Observable true).subscribe(new Observer<Long>() { @Override public void onSubscribe(Disposable d) { System.out.println("--> onSubscribe"); } @Override public void onNext(Long aLong) { System.out.println("--> onNext: " + aLong); } @Override public void onError(Throwable e) { System.out.println("--> onError: " + e); } @Override public void onComplete() { System.out.println("--> onComplete"); } });
Output:
----> resourceSupplier call(1) ----> sourceSupplier apply(1): MyResource{resource='This is Observable resource!'} --> onSubscribe(1) --> onNext(1): 1 --> onNext(1): 2 --> onNext(1): 3 --> onNext(1): 4 --> onNext(1): 5 ----> disposer accept(1): ----> MyResource resource is release. --> onComplete
Javadoc: using(Callable resourceSupplier, Function sourceSupplier, Consumer disposer)
Javadoc: using(Callable resourceSupplier, Function sourceSupplier, Consumer disposer, boolean eager)
12. To
Convert Observable to another object or data structure.
Convert the data sequence emitted by Observable or Observable to another object or data structure. Some of them block until the Observable terminates, and then generate an equivalent object or data structure; others return an Observable that emits that object or data structure.
Because there are many toXXX operator implementations and different variant overloads in rxjava's To operator, we will not expand them in detail here. You can view the official API document See for details.
The following are common To operators:
- toList(): let Observable combine a number of data into a List, then call the onNext method to pass the entire list.
- toMap(Function keySelector,Function valueSelector): toMap collects all data items emitted by the original Observable into a Map (the default is HashMap) and then launches the Map. You can provide a function to generate the Key of the Map, as well as a function to convert the data item to the value stored in the Map (the default data item itself is the value).
- toSortedList(): it will sort the generated list. The default is natural ascending. If the launched data item does not implement the compatible interface, an exception will be thrown. You can also pass a function to compare two data items.
- To multi Map (function keyselector, function valueselector): similar to toMap, the difference is that the value type of the Map it generates is an ArrayList.
Example code:
/** * 1. toList() * Let Observable combine a number of data into a List, then call the onNext method to pass the entire list. */ range.toList() .subscribe(new Consumer<List<Integer>>() { @Override public void accept(List<Integer> integers) throws Exception { System.out.println("--> toList accept(1): " + integers); } }); System.out.println("------------------------------------------"); /** * 2. toMap(Function<? super T, ? extends K> keySelector,Function<? super T, ? extends V> valueSelector) * toMap Collect all data items emitted by the original Observable to a Map (the default is HashMap) and then launch the Map. * You can provide a function to generate the Key of the Map, as well as a function to convert the data item to the value stored in the Map (the default data item itself is the value). */ range.toMap(new Function<Integer, String>() { @Override public String apply(Integer integer) throws Exception { return "key" + integer; // Return a Map key } }, new Function<Integer, Integer>() { @Override public Integer apply(Integer integer) throws Exception { return integer; // Returns the value of a Map } }).subscribe(new SingleObserver<Map<String, Integer>>() { @Override public void onSubscribe(Disposable d) { System.out.println("--> onSubscribe(2)"); } @Override public void onSuccess(Map<String, Integer> stringIntegerMap) { System.out.println("--> onSuccess(2): " + stringIntegerMap); } @Override public void onError(Throwable e) { System.out.println("--> onError(2): " + e); } }); System.out.println("------------------------------------------"); /** * 3. toSortedList() * It will sort the generated list. The default is natural ascending. If the launched data item does not implement the compatible interface, an exception will be thrown. * However, you can also pass a function to compare two data items */ Observable.just(5, 3, 8, 6, 9, 10) .toSortedList() .subscribe(new SingleObserver<List<Integer>>() { @Override public void onSubscribe(Disposable d) { System.out.println("--> onSubscribe(3)"); } @Override public void onSuccess(List<Integer> integers) { System.out.println("--> onSuccess(3): " + integers); } @Override public void onError(Throwable e) { System.out.println("--> onError(3): " + e); } }); System.out.println("------------------------------------------"); /** * 4. toSortedList(Comparator comparator) * * Passing a function comparator to compare two data items sorts the resulting list */ Observable.just(5, 3, 8, 6, 9, 10) .toSortedList(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { System.out.println("--> compare: o1 = " + o1 + ", o2 = " + o2); return o1 - o2; // Sorting logic of comparator } }).subscribe(new SingleObserver<List<Integer>>() { @Override public void onSubscribe(Disposable d) { System.out.println("--> onSubscribe(4)"); } @Override public void onSuccess(List<Integer> integers) { System.out.println("--> onSuccess(4): " + integers); } @Override public void onError(Throwable e) { System.out.println("--> onError(4): " + e); } }); System.out.println("------------------------------------------"); /** * 5. toMultimap(Function<T, K> keySelector, Function<T, V> valueSelector) * Similar to toMap, the difference is whether the value type of the Map it generates is an ArrayList */ range.toMultimap(new Function<Integer, String>() { @Override public String apply(Integer integer) throws Exception { return "key" + integer; // Return a Map key } }, new Function<Integer, Integer>() { @Override public Integer apply(Integer integer) throws Exception { return integer; // Returns the value of a Map } }).subscribe(new SingleObserver<Map<String, Collection<Integer>>>() { @Override public void onSubscribe(Disposable d) { System.out.println("--> onSubscribe(5)"); } @Override public void onSuccess(Map<String, Collection<Integer>> stringCollectionMap) { System.out.println("--> onSuccess(5): " + stringCollectionMap); } @Override public void onError(Throwable e) { System.out.println("--> onError(5): " + e); } });
Output:
--> toList accept(1): [1, 2, 3, 4, 5] ------------------------------------------ --> onSubscribe(2) --> onSuccess(2): {key1=1, key2=2, key5=5, key3=3, key4=4} ------------------------------------------ --> onSubscribe(3) --> onSuccess(3): [3, 5, 6, 8, 9, 10] ------------------------------------------ --> onSubscribe(4) --> compare: o1 = 3, o2 = 5 --> compare: o1 = 8, o2 = 3 --> compare: o1 = 8, o2 = 5 --> compare: o1 = 6, o2 = 5 --> compare: o1 = 6, o2 = 8 --> compare: o1 = 9, o2 = 6 --> compare: o1 = 9, o2 = 8 --> compare: o1 = 10, o2 = 6 --> compare: o1 = 10, o2 = 9 --> onSuccess(4): [3, 5, 6, 8, 9, 10] ------------------------------------------ --> onSubscribe(5) --> onSuccess(5): {key1=[1], key2=[2], key5=[5], key3=[3], key4=[4]}
Javadoc: toList()
Javadoc: toMap(Function keySelector,Function valueSelector)
Javadoc: toSortedList()
Javadoc: toMultimap(Function keySelector, Function valueSelector)
Summary
This section mainly introduces various auxiliary operators in Rxjava, such as delay, timeout, event monitoring and other auxiliary operations, which are very useful in development.
Tip: Rxjava2 version used above: 2.2.12
Rx introduction and explanation and complete catalog reference: Rxjava2 introduction and detailed examples
Instance code: