Estoy usando rxjava en mi aplicación de Android para manejar solicitudes de red de forma asincrónica. Ahora me gustaría volver a intentar una solicitud de red fallida solo después de que haya pasado un cierto tiempo.
¿Hay alguna forma de usar retry () en un Observable pero reintentar solo después de un cierto retraso?
¿Hay alguna manera de hacerle saber al Observable que se está reintentando actualmente (en lugar de intentarlo por primera vez)?
Eché un vistazo a debounce () / throttleWithTimeout () pero parecen estar haciendo algo diferente.
Editar:
Creo que encontré una forma de hacerlo, pero me interesaría la confirmación de que esta es la forma correcta de hacerlo o de otras formas mejores.
Lo que estoy haciendo es esto: en el método call () de mi Observable.OnSubscribe, antes de llamar al método Subscribers onError (), simplemente dejo que el Thread duerma durante la cantidad de tiempo deseada. Entonces, para volver a intentarlo cada 1000 milisegundos, hago algo como esto:
@Override
public void call(Subscriber<? super List<ProductNode>> subscriber) {
try {
Log.d(TAG, "trying to load all products with pid: " + pid);
subscriber.onNext(productClient.getProductNodesForParentId(pid));
subscriber.onCompleted();
} catch (Exception e) {
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e.printStackTrace();
}
subscriber.onError(e);
}
}
Dado que este método se ejecuta en un subproceso IO de todos modos, no bloquea la interfaz de usuario. El único problema que puedo ver es que incluso el primer error se informa con retraso, por lo que el retraso existe incluso si no hay reintento (). Me gustaría más si el retraso no se aplicara después de un error, sino antes de un reintento (pero no antes del primer intento, obviamente).
Error:(73, 20) error: incompatible types: RetryWithDelay cannot be converted to Func1<? super Observable<? extends Throwable>,? extends Observable<?>>
RetryWithDelay
a esto: pastebin.com/6SiZeKnCInspirado por la respuesta de Paul , y si no le preocupan los
retryWhen
problemas indicados por Abhijit Sarkar , la forma más sencilla de retrasar la resuscripción con rxJava2 incondicionalmente es:Es posible que desee ver más ejemplos y explicaciones sobre retryWhen y repeatWhen .
fuente
Este ejemplo funciona con jxjava 2.2.2:
Vuelva a intentarlo sin demora:
Reintentar con retraso:
Nuestro único fuente falla si falla someConnection.send (). Cuando eso sucede, el observable de fallas dentro de retryWhen emite el error. Retrasamos esa emisión en 300 ms y la enviamos de vuelta para señalar un reintento. take (5) garantiza que nuestro observable de señalización terminará después de recibir cinco errores. retryWhen ve la terminación y no vuelve a intentarlo después del quinto error.
fuente
Esta es una solución basada en los fragmentos de código que vi de Ben Christensen, RetryWhen Example y RetryWhenTestsConditional (tuve que cambiar
n.getThrowable()
an
para que funcione). Solía Evant / Gradle-retrolambda para hacer el trabajo notación lambda en Android, pero usted no tiene que utilizar lambdas (aunque es muy recomendable). Para la demora, implementé un retroceso exponencial, pero puede conectar la lógica de retroceso que desee allí. Para completar, agregué los operadoressubscribeOn
yobserveOn
. Estoy usando ReactiveX / RxAndroid paraAndroidSchedulers.mainThread()
.fuente
Observable
objetos?kjones
solución y me está funcionando perfecto, graciasen lugar de usar MyRequestObservable.retry, uso una función contenedora retryObservable (MyRequestObservable, retrycount, seconds) que devuelve un nuevo Observable que maneja la indirección del retraso para que pueda hacerlo
fuente
retryWhen
es un operador complicado, quizás incluso con errores. El documento oficial y al menos una respuesta aquí usan elrange
operador, que fallará si no se realizan reintentos. Vea mi discusión con el miembro de ReactiveX, David Karnok.Mejoré la respuesta de kjones cambiando
flatMap
aconcatMap
y añadiendo unaRetryDelayStrategy
clase.flatMap
no conserva el orden de emisión mientras loconcatMap
hace, lo cual es importante para retrasos con retroceso. ElRetryDelayStrategy
, como su nombre lo indica, permite que el usuario elija entre varios modos de generar retrasos en los reintentos, incluido el retroceso. El código está disponible en mi GitHub completo con los siguientes casos de prueba:Ver
setRandomJokes
método.fuente
Ahora, con la versión 1.0+ de RxJava, puede usar zipWith para lograr reintentar con retraso.
Añadiendo modificaciones a la respuesta de kjones .
Modificado
fuente
La misma respuesta que la de kjones pero actualizada a la última versión para la versión 2.x de RxJava : ('io.reactivex.rxjava2: rxjava: 2.1.3')
Uso:
// Agregue lógica de reintento al observable existente. // Reintentar un máximo de 3 veces con un retraso de 2 segundos.
fuente
Según la respuesta de kjones, aquí está la versión Kotlin de RxJava 2.x reintentar con un retraso como extensión. Reemplazar
Observable
para crear la misma extensión paraFlowable
.Entonces utilícelo en observables
observable.retryWithDelay(3, 1000)
fuente
Single
también?flatMap
habrá que usarFlowable.timer
yFlowable.error
aunque la función seaSingle<T>.retryWithDelay
.Puede agregar un retraso en el Observable devuelto en el retryWhen Operator
Puedes ver más ejemplos aquí. https://github.com/politrons/reactive
fuente
Simplemente hazlo así:
fuente
Para la versión Kotlin y RxJava1
fuente
(Kotlin) He mejorado un poco el código con retroceso exponencial y emisión de defensa aplicada de Observable.range ():
fuente
en caso de que necesite imprimir el recuento de reintentos, puede usar el ejemplo proporcionado en la página wiki de Rxjava https://github.com/ReactiveX/RxJava/wiki/Error-Handling-Operators
fuente