Вызвать два независимых метода с использованием Rx - PullRequest
0 голосов
/ 25 июня 2018

У меня есть два асинхронных метода, которые нужно вызывать во время одной операции.Каждый метод может быть успешно завершен или получен с ошибкой.В случае ошибки я должен повторить вызов каждого метода еще раз с задержкой в ​​2 секунды.Значит, мне надо вызывать оба метода, несмотря на результат одного из них.В обратном вызове ошибки я хочу знать, в каком методе произошла ошибка, или в обоих методах.

Кажется, я должен использовать Completable для этого, но я абсолютно новичок в Rx.

private void method1(final CompletableEmitter e, String path){
Database.getInstance().getReference(path).addListener(new Listener() {
            @Override
            public void onDataChange(Data data) {
               //todo something
               e.onComplete();                
            }
            @Override
            public void onCancelled(DatabaseError databaseError) {
               e.onError(new Throwable(databaseError.getMessage()));
            }
        });
}

Метод 2 такой же.Следующий код не работает должным образом.

    Completable completable1 = Completable.create(method1(e););
    Completable completable2 = Completable.create(method2(e););

    completable1
            .doOnError(…)
            .retry(1)
            .andThen(completable2 //never called if completable1 gets onError each time
                    .retry(1)
                    .doOnError(…))
            .subscribe(…).dispose();

1 Ответ

0 голосов
/ 25 июня 2018

У вас есть много способов сделать это. Я собираюсь ограничиться, чтобы объяснить, как этого добиться, используя два Completable s

Допустим, у вас есть два завершаемых:

Completable doSomething = ...
Completable doSomethingElse = ...

Чтобы выполнить их последовательно, Вы можете объединить их, используя оператор andThen. Затем, чтобы отложить повторную попытку при возникновении ошибки, вы можете использовать retryWhen:

doSomething.andThen(doSomethingElse)
    .retryWhen { Flowable.timer(2, TimeUnit.SECONDS) }
    .subscribe()

Этот фрагмент выше будет повторяться бесконечно, если ошибка постоянно возникает. Чтобы выйти за пределы, вы можете ограничить количество попыток, используя:

.retryWhen { errors ->
    val retryCounter = AtomicInteger()
    errors.flatMap {
        if (retryCounter.getAndIncrement() <= 3)
            Flowable.timer(2, TimeUnit.SECONDS)
        else Flowable.error(it)
    }
}

Если вы хотите повторить попытку только при возникновении данного типа ошибки, вы можете использовать:

.retryWhen { errors ->
    val retryCounter = AtomicInteger()
    errors.flatMap {
        if (it is YourSpecficError && retryCounter.getAndIncrement() <= 3)
            Flowable.timer(2, TimeUnit.SECONDS)
        else Flowable.error(it)
    }
}

Если вы хотите повторить попытку независимо, вы можете использовать:

doSomething.retryWhen { ... }
    .andThen(doSomethingElse.retryWhen { ... })
    .subscribe()

Кроме того, чтобы избежать повторных попыток при дублировании логики, вы можете заключить это в функцию расширения:

fun Completable.retryDelayed(): Completable {
    return this.retryWhen { errors ->
        val retryCounter = AtomicInteger()
        errors.flatMap {
            if (it is YourSpecficError && retryCounter.getAndIncrement() <= 3)
                Flowable.timer(2, TimeUnit.SECONDS)
            else Flowable.error(it)
        }
    }
}

Если вы хотите запустить ваши завершаемые таблицы параллельно, вы можете использовать оператор merge:

Completable doAll = Completable.merge(listOf(doSomething, doSomething))
...