J'utilise rxjava dans mon application Android pour gérer les demandes réseau de manière asynchrone. Maintenant, je voudrais réessayer une demande réseau ayant échoué seulement après un certain temps.
Existe-t-il un moyen d'utiliser retry () sur un observable mais de ne réessayer qu'après un certain délai?
Existe-t-il un moyen de faire savoir à l'Observable qu'il est actuellement réessayé (par opposition à essayé pour la première fois)?
J'ai jeté un coup d'œil à debounce () / throttleWithTimeout () mais ils semblent faire quelque chose de différent.
Éditer:
Je pense avoir trouvé un moyen de le faire, mais je serais intéressé soit par la confirmation que c'est la bonne façon de le faire, soit par d'autres, de meilleures façons.
Voici ce que je fais: dans la méthode call () de mon Observable.OnSubscribe, avant d'appeler la méthode Subscribers onError (), je laisse simplement le Thread dormir pendant la durée souhaitée. Donc, pour réessayer toutes les 1000 millisecondes, je fais quelque chose comme ceci:
@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);
}
}
Étant donné que cette méthode s'exécute de toute façon sur un thread IO, elle ne bloque pas l'interface utilisateur. Le seul problème que je peux voir est que même la première erreur est signalée avec un délai, donc le délai est là même s'il n'y a pas de nouvelle tentative (). Je préfère que le délai ne soit pas appliqué après une erreur mais plutôt avant une nouvelle tentative (mais pas avant le premier essai, évidemment).
Error:(73, 20) error: incompatible types: RetryWithDelay cannot be converted to Func1<? super Observable<? extends Throwable>,? extends Observable<?>>
RetryWithDelay
pour ceci: pastebin.com/6SiZeKnCInspiré par la réponse de Paul , et si vous n'êtes pas concerné par les
retryWhen
problèmes évoqués par Abhijit Sarkar , le moyen le plus simple de retarder le réabonnement avec rxJava2 sans condition est:Vous voudrez peut-être voir plus d'exemples et d'explications sur retryWhen et repeatWhen .
la source
Cet exemple fonctionne avec jxjava 2.2.2:
Réessayez sans tarder:
Réessayer avec un délai:
Notre unique source échoue si someConnection.send () échoue. Lorsque cela se produit, l'observable des échecs à l'intérieur de retryWhen émet l'erreur. Nous retardons cette émission de 300 ms et la renvoyons pour signaler une nouvelle tentative. take (5) garantit que notre observable de signalisation se terminera après avoir reçu cinq erreurs. retryWhen voit l'arrêt et ne réessaye pas après le cinquième échec.
la source
Il s'agit d'une solution basée sur les extraits de Ben Christensen que j'ai vus, RetryWhen Example et RetryWhenTestsConditional (j'ai dû changer
n.getThrowable()
pourn
que cela fonctionne). J'ai utilisé evant / gradle-retrolambda pour faire fonctionner la notation lambda sur Android, mais vous n'avez pas besoin d'utiliser lambdas (bien que cela soit fortement recommandé). Pour le délai, j'ai implémenté un back-off exponentiel, mais vous pouvez y brancher la logique de backoff que vous souhaitez. Pour être complet, j'ai ajouté les opérateurssubscribeOn
etobserveOn
. J'utilise ReactiveX / RxAndroid pour leAndroidSchedulers.mainThread()
.la source
Observable
objets?kjones
solution et ça marche parfait pour moi, merciau lieu d'utiliser MyRequestObservable.retry J'utilise une fonction wrapper retryObservable (MyRequestObservable, retrycount, seconds) qui renvoie un nouvel Observable qui gère l'indirection pour le délai afin que je puisse faire
la source
retryWhen
est un opérateur compliqué, peut-être même bogué. Le document officiel et au moins une réponse ici utilisent l'range
opérateur, qui échouera s'il n'y a pas de nouvelle tentative. Voir ma discussion avec David Karnok, membre de ReactiveX.Je me suis amélioré sur la réponse de kjones en changeant
flatMap
àconcatMap
et en y ajoutant uneRetryDelayStrategy
classe.flatMap
ne préserve pas l'ordre d'émission tandis queconcatMap
fait, ce qui est important pour les retards avec recul. LeRetryDelayStrategy
, comme son nom l'indique, permet à l'utilisateur de choisir parmi différents modes de génération de délais de relance, y compris l'arrêt. Le code est disponible sur mon GitHub avec les cas de test suivants:Voir la
setRandomJokes
méthode.la source
Maintenant, avec la version 1.0+ de RxJava, vous pouvez utiliser zipWith pour effectuer une nouvelle tentative avec un délai.
Ajout de modifications à la réponse kjones .
Modifié
la source
Même réponse que depuis kjones mais mise à jour vers la dernière version Pour la version RxJava 2.x : ('io.reactivex.rxjava2: rxjava: 2.1.3')
Usage:
// Ajout d'une logique de nouvelle tentative à l'observable existante. // Réessayez au maximum 3 fois avec un délai de 2 secondes.
la source
Basé sur la réponse de kjones, voici la version Kotlin de RxJava 2.x réessayer avec un retard comme extension. Remplacez
Observable
pour créer la même extension pourFlowable
.Ensuite, utilisez-le simplement sur observable
observable.retryWithDelay(3, 1000)
la source
Single
également?flatMap
qu'il faudra utiliserFlowable.timer
etFlowable.error
même si la fonction estSingle<T>.retryWithDelay
.Vous pouvez ajouter un délai dans l'observable renvoyé lors de la nouvelle tentative.
Vous pouvez voir plus d'exemples ici. https://github.com/politrons/reactive
la source
Faites-le simplement comme ceci:
la source
Pour la version Kotlin & RxJava1
la source
(Kotlin) J'ai un peu amélioré le code avec un ralentissement exponentiel et une émission de défense appliquée de Observable.range ():
la source
dans le cas où vous devez imprimer le nombre de tentatives, vous pouvez utiliser l'exemple fourni sur la page wiki de Rxjava https://github.com/ReactiveX/RxJava/wiki/Error-Handling-Operators
la source