Объединение RxJava Completables

Объединение RxJava Completables

1. обзор

В этом руководстве мы будем играть с типомRxJava’sCompletable, который представляет результат вычисления без фактического значения.

2. Зависимость RxJava

Давайте включим зависимость RxJava 2 в наш проект Maven:


    io.reactivex.rxjava2
    rxjava
    2.2.2

Обычно мы можем найти последнюю версию наMaven Central.

3. Завершаемый Тип

Completableis similar to Observable with the only exception that the former emits either completion or error signals but no items. КлассCompletable содержит несколько удобных методов для его создания или получения из различных реактивных источников.

Мы можем создать экземпляр, который завершается немедленно, используяCompletable.complete().

Затем мы можем наблюдать его состояние, используяDisposableCompletableObserver:

Completable
  .complete()
  .subscribe(new DisposableCompletableObserver() {
    @Override
    public void onComplete() {
        System.out.println("Completed!");
    }

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

Кроме того, мы можем построить экземплярCompletable изCallable, Action, and Runnable:

Completable.fromRunnable(() -> {});

Кроме того, мы можем получить экземплярыCompletable из других типов, используяCompletable.from() или вызываяignoreElement() дляMaybe,Single,Flowable иObservableсами источники:

Flowable flowable = Flowable
  .just("request received", "user logged in");
Completable flowableCompletable = Completable
  .fromPublisher(flowable);
Completable singleCompletable = Single.just(1)
  .ignoreElement();

4. ЦепочкаCompletables

Мы можем использовать цепочкуCompletables во многих реальных случаях использования, когда мы заботимся только об успехе операции:

  • Действия «все или ничего», такие как выполнение запроса PUT для обновления удаленного объекта с последующим обновлением локальной базы данных в случае успеха

  • Постфактум регистрации и ведения журнала

  • Оркестровка нескольких действий, например запуск задания аналитики после выполнения действия приема внутрь

Мы будем делать примеры простыми и независимыми от проблем. Допустим, у нас есть несколько экземпляровCompletable:

Completable first = Completable
  .fromSingle(Single.just(1));
Completable second = Completable
  .fromRunnable(() -> {});
Throwable throwable = new RuntimeException();
Completable error = Single.error(throwable)
  .ignoreElement();

To combine two Completables into a single one, we can use the andThen() operator:

first
  .andThen(second)
  .test()
  .assertComplete();

Мы можем связать столькоCompletables, сколько необходимо. При этомif at least one of the sources fails to complete, resulting Completable won’t fire onComplete() as well:

first
  .andThen(second)
  .andThen(error)
  .test()
  .assertError(throwable);

Кроме того,if one of the sources is infinite or doesn’t reach onComplete for some reason, the resulting Completable will never fire onComplete() nor onError() as well.

Хорошо, что мы все еще можем проверить этот сценарий:

...
  .andThen(Completable.never())
  .test()
  .assertNotComplete();

5. Составление серии дополнений

Представьте, что у нас есть группаCompletables.. На практике предположим, что нам нужно зарегистрировать пользователя в нескольких отдельных подсистемах.

To join all Completables into a single one, we can use the merge() family of methods. Операторmerge() позволяет подписаться на все источники.

Результирующий экземплярcompletes once all of the sources are completed. Кроме того, он завершаетсяonError, когда любой из источников выдает ошибку:

Completable.mergeArray(first, second)
  .test()
  .assertComplete();

Completable.mergeArray(first, second, error)
  .test()
  .assertError(throwable);

Давайте перейдем к немного другому варианту использования. Допустим, нам нужно выполнить действие для каждого элемента, полученного изFlowable.

Затем нам нужен одинCompletable как для завершения восходящего потока, так и для всех действий на уровне элементов. В этом случае на помощь приходит операторflatMapCompletable ():

Completable allElementsCompletable = Flowable
  .just("request received", "user logged in")
  .flatMapCompletable(message -> Completable
      .fromRunnable(() -> System.out.println(message))
  );
allElementsCompletable
  .test()
  .assertComplete();

Точно так же вышеуказанный метод доступен для остальных базовых реактивных классов, таких какObservable,Maybe илиSingle..

В качестве практического контекста дляflatMapCompletable() мы могли бы подумать о том, чтобы украсить каждый элемент каким-либо побочным эффектом. Мы можем записать запись в журнал для каждого выполненного элемента или сделать снимок хранилища после каждого успешного действия.

Наконец,we may need to construct a Completable from a couple of other sources and get it terminated as soon as either of them completes. Вот здесь могут помочь операторыamb.

Префиксamb является сокращением от «неоднозначного», подразумевая неопределенность относительно того, какой именноCompletable будет завершен. Например,ambArray():

Completable.ambArray(first, Completable.never(), second)
  .test()
  .assertComplete();

Обратите внимание, что приведенный вышеCompletable may также завершаетсяonError() вместоonComplete() в зависимости от того, какой источник завершается первым:

Completable.ambArray(error, first, second)
  .test()
  .assertError(throwable);

Кроме того, как только первый источник завершает работу, оставшиеся источники гарантированно удаляются.

Это означает, что все оставшиеся запущенныеCompletables останавливаются черезDisposable.dispose(), а подписка на соответствующийCompletableObservers будет отменена.

Что касается практического примера, мы можем использоватьamb() при потоковой передаче файла резервной копии на несколько эквивалентных удаленных хранилищ. И мы завершим процесс, как только закончится первая лучшая резервная копия, или повторим процесс при ошибке.

6. Заключение

В этой статье мы кратко рассмотрели стильCompletable RxJava.

Мы начали с различных вариантов получения экземпляровCompletable, а затем связали и составилиCompletables с помощью операторовandThen(), merge(), flatMapCompletable(), andamb…().

Мы можем найти исходный код для всех примеров кодаover on GitHub.