RxJava 1.x Notes: Creative Operators

Keywords: Java Programming

This article is for reading. Official Documents Notes.  
Authors: shixinzhang (Baidu search for "shixinzhang CSDN" can find me)

RxJava has also been used for some time, so many operators do not want to remember, only to check when they encounter, the number of checks is too many, it feels inefficient, it is better to go through the official documents first.

So in the next few articles, we will brush RxJava official documents together. This process may be very boring, but like the Shaolin Temple in the movie, only through boring learning to master the basic skills, then we can consider how to apply, refueling! ___________.

After reading this article, you will understand:

Creative operator

Creative operators are the operators used to create Observable.

create

In RxJava, create() specifies the type of data to be created by passing an Observable.OnSubscribe to create an Observable, Observable.OnSubscribe generic parameter:

//create the Observed with the create Method
mObservable = Observable.create(new Observable.OnSubscribe<String>() {
    /**
     * When observable is subscribed, the call() method is automatically called, triggering events in turn.
     * In fact, it calls the subscriber's callback method, which implements the event transfer from the observer to the observer.
     * @param subscriber
     */
    @Override
    public void call(Subscriber<? super String> subscriber) {
        if (!subscriber.isUnsubscribed()) {
            //There may be complex event sending rules
            for (int i = 0; i < 5; i ++) {
                subscriber.onNext("next 1");
            }
            subscriber.onCompleted();   //Complete must be called
        }
        //In unexpected circumstances, onError is called
        subscriber.onError(new Throwable("Error message"));
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

In create(), onNext(), onCompleted() and onError() are invoked according to the status of the created task.

In create(), it is best to call isUnsubscribed() to check the subscription status of the observer so that useless creation can be avoided without the observer.

create() is not executed on any particular scheduler by default.

defer

Defer means "defer, defer".

The defer operator, which is created using an Observable factory method only after an observer subscription, repeats this operation every time a new observer subscription occurs.

Subscribers assume that they subscribe to the same data source, but actually they subscribe to different Observable s.

The corresponding implementation in RxJava is defer(), which accepts a parameter of type Func0 < Observable < T>:

public final static <T> Observable<T> defer(Func0<Observable<T>> observableFactory) {
    return create(new OnSubscribeDefer<T>(observableFactory));
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

We can pass in an anonymous inner class of Func0 < Observable < T > whose generic parameter is the data type:

mObservable = Observable.defer(new Func0<Observable<String>>() {
    @Override
    public Observable<String> call() {
        return "test";
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Empty

Empty is used to create an Observable that does not emit any data but emits a termination message.

The corresponding implementation in RxJava is the empty() method:

public final static <T> Observable<T> empty() {
    return (Observable<T>) EmptyHolder.INSTANCE;
}
//Lazy loading, static inner class singleton, launching only one onCompleted()
private static final class EmptyHolder {
    final static Observable<Object> INSTANCE = create(new OnSubscribe<Object>() {
        @Override
        public void call(Subscriber<? super Object> subscriber) {
            subscriber.onCompleted();
        }
    });
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

It is simple to use and has no parameters:

//Create an onCompleted() that does not emit any data.
mObservable = Observable.empty();
  • 1
  • 2
  • 1
  • 2

Never

Never is used to create an Observable that does not emit any data or termination messages.

The corresponding implementation in RxJava is the never() method:

public final static <T> Observable<T> never() {
    return NeverObservable.instance();
}
private static class NeverObservable<T> extends Observable<T> {

    private static class Holder {
        static final NeverObservable<?> INSTANCE = new NeverObservable<Object>();
    }

    @SuppressWarnings("unchecked")
    static <T> NeverObservable<T> instance() {
        return (NeverObservable<T>) Holder.INSTANCE;
    }

    NeverObservable() {
        super(new OnSubscribe<T>() {
            @Override
            public void call(Subscriber<? super T> observer) {
                // do nothing
            }

        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

You can see that the NeverObservable returned by this method does not send any messages, which is similar to empty():

//No message will be sent.
mObservable = Observable.never();
  • 1
  • 2
  • 1
  • 2

Throw

Throw is used to create an Observable that does not emit any data but emits error messages.

The corresponding implementation in RxJava is the error() method:

public final static <T> Observable<T> error(Throwable exception) {
    return new ThrowObservable<T>(exception);
}
private static class ThrowObservable<T> extends Observable<T> {

    public ThrowObservable(final Throwable exception) {
        super(new OnSubscribe<T>() {

            @Override
            public void call(Subscriber<? super T> observer) {
                observer.onError(exception);
            }

        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

As you can see, error() emits an onError() event.

It's easy to use, just pass in a Throwable:

//Only error messages will be sent.
mObservable = Observable.error(new Throwable("error message"));
  • 1
  • 2
  • 1
  • 2

The Observable created by the Empty/Never/Throw three operators is special and is generally used for test Sometimes, it also combines other data sources as parameters of other operators.

From

From can convert other objects or data types into Observables.

When using Observable, it is preferable that all data sources are of Observable type, which makes it very convenient to cooperate with operators. At this point, if there are data types other than Observable, we'd better use some operators to convert other types to Observable.

Iterable iterators, for example, can be converted into a series of synchronous Observables; Future can be converted to Observables that emit only one element at a time. By explicitly converting other types to Observable, you can easily appreciate the convenience of Rx.

Most ReactiveX implementation languages provide specific objects and data structure Method to convert to Observables.

The corresponding implementation in RxJava is from():

public final static <T> Observable<T> from(T[] array) {
    return from(Arrays.asList(array));
}
public final static <T> Observable<T> from(Iterable<? extends T> iterable) {
    return create(new OnSubscribeFromIterable<T>(iterable));
}
public static <T> Observable<T> from(Future<? extends T> future) {
    return (Observable<T>)unsafeCreate(OnSubscribeToObservableFuture.toObservableFuture(future));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

from() supports parameters such as arrays, Iterable, Future, that is, this operator can convert data of array, Iterable, and Future types to Observable.

For Iterable and arrays, the converted Observable emits Iterable or every item in the array.

Students who don't know Iterable can read this article: Java Collection Source Parsing: Iterator.

Use examples:

private void createObservables() {
    String[] words = {"shixin", "is", "cute"};
    Observable<String> from = Observable.from(words);
    from.subscribe(new Subscriber<String>() {
        @Override
        public void onCompleted() {
            System.out.println("onCompleted");
        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(String s) {
            System.out.println("onNext: " + s);
        }
    });
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

Operation results:

from() is not executed on any particular scheduler by default. We can pass Scheduler as the second parameter to Observable, which will execute on the specified thread.

Interval

Interval is used to create an Observable that sends an incremental sequence of integers at a specified time interval.

The Observable returned by the Interval operator emits an infinitely increasing sequence of integers at intervals.

The corresponding implementation in RxJava is interval(), which accepts a parameter representing the time interval and a parameter representing the time unit:

public static Observable<Long> interval(long interval, TimeUnit unit) {
    return interval(interval, interval, unit, Schedulers.computation());
}
public static Observable<Long> interval(long initialDelay, long period, TimeUnit unit, Scheduler scheduler) {
    return unsafeCreate(new OnSubscribeTimerPeriodically(initialDelay, period, unit, scheduler));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Use examples:

private void createObservableWithInterval() {
    Observable<Long> interval = Observable.interval(1, TimeUnit.SECONDS);
    interval.subscribe(getPrintSubscriber());
}

/**
 * Subscribers for printing results
 * @param <T>
 * @return
 */
private <T> Subscriber<T> getPrintSubscriber() {
    return new Subscriber<T>() {
        @Override
        public void onCompleted() {
            System.out.println("onCompleted");
        }

        @Override
        public void onError(Throwable e) {
            System.out.println("onError: " + e.getMessage());
        }

        @Override
        public void onNext(T t) {
            System.out.println("onNext: " + t);
            if ((Long)t > 10){
                unsubscribe();
            }
        }
    };
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

In this example, we use interval() to create an Observable that emits an incremental sequence of integers. In onNext(), we cancel the subscription when t > 10. Operation results:

Just

Just is used to create an Observable that emits specific elements.

Just operator is used to convert an element into Observable and then emit it.

Just is somewhat similar to From, except that From takes out the array or Iterable data and transmits it one by one; Just simply transmits it as it is, sending it as a single data at a time.

The corresponding implementation in RxJava is just():

public static <T> Observable<T> just(final T value) {
    return ScalarSynchronousObservable.create(value);
}
public static <T> Observable<T> just(T t1, T t2) {
    return from((T[])new Object[] { t1, t2 });
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

As you can see, just() of multiple parameters is actually called from().

Use examples:

private void createObservableWithJust() {
    String[] words = {"shixin", "is", "cute"};
    Observable<String[]> just = Observable.just(words);
    just.subscribe(getPrintSubscriber());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

We pass it to just() an array, and the output is still an array object; to a null, the output is null:

As you can see, just() is exactly the same as the name, which is to send the converted data directly.

Note that if you pass null to just, it will return an Observable and emit a null instead of creating an empty Observable. If you want to create an empty one, you need to use the Empty operator.

Range

Range is used to create an Observable that transmits an integer sequence of specified ranges.

The corresponding implementation in RxJava is range():

public static Observable<Integer> range(int start, int count) {
    if (count < 0) {
        throw new IllegalArgumentException("Count can not be negative");
    }
    if (count == 0) {
        return Observable.empty();
    }
    if (start > Integer.MAX_VALUE - count + 1) {
        throw new IllegalArgumentException("start + count can not exceed Integer.MAX_VALUE");
    }
    if (count == 1) {
        return Observable.just(start);
    }
    return Observable.unsafeCreate(new OnSubscribeRange(start, start + (count - 1)));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

As you can see, just() accepts two parameters, the first is the starting value and the second is the number. If you set the second value to 0, you will not emit data; if you set it to a negative number or the starting value is too large, you will throw an exception.

Use examples:

private void createObservableWithRange() {
    Observable<Integer> range = Observable.range(3, 5);
    range.subscribe(this.<Integer>getPrintSubscriber());
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

Operation results:

Repeat

Repeat is used to create an Observable that emits specific data multiple times.

The implementation of repeat() in RxJava is not static, that is to say, it can not be used to create Observable, only to repeat the existing Observable, parameters specify the number of repeats.

public final Observable<T> repeat(final long count) {
    return OnSubscribeRedo.<T>repeat(this, count);
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

When using it, you need to create an Observable and repeat it:

private void createObservableWithRepeat() {
    String[] words = {"shixin", "is", "cute"};
    Observable<String> from = Observable.from(words);
    from.repeat(2)
            .subscribe(getPrintSubscriber());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Operation results:

As you can see, when repeat() receives the onCompleted() event, it triggers a re-subscription.

The repeat operator is executed by default on the trampoline scheduler. We can specify Scheduler by ourselves.

RepeatWhen

RepeatWhen is relatively confusing.

Repeat receives onCompleted() events and triggers re-subscription, while Repeat When adds control over when to re-subscribe on its basis.

RepeatWhen an onCompleted event is received, a condition check is performed, and then a corresponding retransmit operation is performed; when an onError event is received, the repetition is stopped.

The corresponding implementation in RxJava is repeatWhen():

public final Observable<T> repeatWhen(final Func1<? super Observable<? extends Void>, ? extends Observable<?>> notificationHandler) {
    return OnSubscribeRedo.repeat(this, InternalObservableUtils.createRepeatDematerializer(notificationHandler));
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

As you can see, the first parameter of repeatWhen() is the processing function of the input Observable, and the second parameter is the processing strategy.

Because parameters are called only when onCompleted is called, it is of Void type.

Use examples:

Observable.unsafeCreate(new Observable.OnSubscribe<String>() {
    @Override
    public void call(final Subscriber<? super String> subscriber) {
        for (int i = 0; i < 5; i++) {
                subscriber.onNext("item " + i);
        }
        subscriber.onCompleted();
    }
}).repeatWhen(new Func1<Observable<? extends Void>, Observable<?>>() {
    @Override
    public Observable<?> call(final Observable<? extends Void> completed) {
        //Every time onCompleted is called, it enters here, where you need to decide whether you need to re-subscribe or not.
        return completed.delay(5, TimeUnit.SECONDS);
    }
}).subscribe(getPrintSubscriber());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

Every time onCompleted event is launched, anonymous internal class parameters of repeatWhen are entered, in which we delayed processing.

Operation results:

As you can see, it's repeated every five seconds.

Start

Start creates an Observable for the return value of the emitter function.

There are many ways to get the results of calculation in programming languages, such as functions, futures, actions, callables, runnables and so on. Start operators can turn their results into Observable, making it easier to operate.

There are many implementations of Start in RxJava, which belong to the rxjava-async module.

In RxJava, the From operator can convert Future to Observable, similar to start.

Timer

Timer is used to create an Observable that emits a value after a specified delay.

The corresponding implementation in RxJava is timer:

public static Observable<Long> timer(long delay, TimeUnit unit) {
    return timer(delay, unit, Schedulers.computation());
}
public static Observable<Long> timer(long delay, TimeUnit unit, Scheduler scheduler) {
    return unsafeCreate(new OnSubscribeTimerOnce(delay, unit, scheduler));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

timer() returns an Observable that emits a number of zeros after delaying a given time.

private void createObservableWithTimer() {
    Observable.timer(3, TimeUnit.SECONDS)
            .subscribe(this.<Long>getPrintSubscriber());
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

Operation results:

We have finished about one fifth of the process, perseverance is victory!!!

Thanks

http://reactivex.io/documentation/operators.html 
http://www.jianshu.com/p/023a5f60e6d0

Posted by wmac on Wed, 12 Jun 2019 10:36:45 -0700