Kotlin, RxJava2: создайте и повторите попытку после взаимодействия с пользователем - PullRequest
0 голосов
/ 12 марта 2019

за последние два дня я много читал об операторе rxJava retryWhen. Здесь , здесь , здесь и еще кое-что я забыл.

Но, к сожалению, я не могу заставить его работать. Я пытаюсь добиться того, чтобы я делал вызов API. Если вызов возвращает ошибку, я показываю пользователю SnackBar с кнопкой перезагрузки. Если пользователь нажимает эту кнопку, я хотел бы повторно подписаться на цепочку.

Вот мой код:

interface RetrofitApi {

@GET("/v1/loadMyData")
fun getMyData(): Single<Response<DataResponse>>
}

Где Ответ от модернизации2. Мне нужно обернуть класс данных, чтобы проверить, был ли ответ успешным.

Следующее веселье вызывается в хранилище из ViewModel:

override fun loadMyData(): Observable<Resource<DataResponse>> {
    return retrofitApi
            .getMyData()
            .compose(getRetryTransformer())
            .toObservable()
            .compose(getResponseTransformer())
}

Resource - еще одна оболочка для состояния вызова (SUCCESS, ERROR, LOADING).

И, наконец, Трансформер:

private fun <Data> getRetryTransformer(): SingleTransformer<Response<Data>, Response<Data>> {
    return SingleTransformer { singleResponse ->
        singleResponse
                .onErrorReturn {
                    singleResponse.blockingGet()
                }
                .retryWhen { errors ->
                    errors.zipWith(retrySubject.toFlowable(BackpressureStrategy.LATEST),
                            BiFunction<Throwable, Boolean, Flowable<Throwable>> { throwable: Throwable, isRetryEnabled: Boolean ->
                                if (isRetryEnabled) {
                                    Flowable.just(null)
                                } else {
                                    Flowable.error(throwable)
                                }
                            })
                }
    }
}

RetrySubject:

private val retrySubject = PublishSubject.create<Boolean>()

И когда пользователь нажимает кнопку повтора, я звоню:

retrySubject.onNext(true)

Теперь проблема в том, что ошибка не возвращается в ViewModel и SnackBar никогда не отображается. Я попытался onErrorResumeNext (), но безуспешно. Вся попытка когда / zip с частью, кажется, работает. Потому что в репозитории есть еще несколько вызовов API без повтора (пока) и там отображается SnackBar. Это означает, что я делаю другой вызов, где отображается SnackBar -> нажатие кнопки, и преобразование повторных попыток работает, как и ожидалось.

Если вам нужна дополнительная информация, пожалуйста, не стесняйтесь спрашивать! Любая помощь приветствуется!

1 Ответ

1 голос
/ 12 марта 2019

Странно, как только вы делаете это правильно, это работает. Я как-то перечитал, что мне нужно в doOnError {...}, чтобы показать мою Снэк-бар.

Вот мой рабочий повторный трансформатор:

private fun <Data> getRetryTransformer(): SingleTransformer<Response<Data>, Response<Data>> {
    return SingleTransformer { singleResponse ->
        singleResponse
                .doOnError {
                    errorEventSubject.onNext(it)
                }
                .retryWhen { errors ->
                    errors.zipWith(retrySubject.toFlowable(BackpressureStrategy.LATEST),
                            BiFunction<Throwable, Boolean, Flowable<Throwable>> { throwable: Throwable, isRetryEnabled: Boolean ->
                                if (isRetryEnabled) {
                                    Flowable.just(throwable)
                                } else {
                                    Flowable.error(throwable)
                                }
                            })
                }
    }
}

И цепочка теперь выглядит вот так (и я думаю, что это прекрасно):

override fun loadMyData(): Observable<Resource<DataResponse>> {
    return retrofitApi
            .getMyData()
            .compose(getRetryTransformer())
            .toObservable()
            .compose(getResponseTransformer())
}

Что еще мне нужно, чтобы распространить ошибку в моей ViewModel, это второй объект PublishSubject:

private val errorEventSubject = PublishSubject.create<Throwable>()

А во ViewModel я наблюдаю за изменениями и показываю снэк-бар. Вот и все.

...