web-dev-qa-db-fra.com

RxJava: enchaîner les observables

Est-il possible d'implémenter quelque chose comme le chaînage suivant en utilisant RxJava:

loginObservable()
   .then( (someData) -> {
      // returns another Observable<T> with some long operation
      return fetchUserDataObservable(someData);

   }).then( (userData) -> {
      // it should be called when fetching user data completed (with userData of type T)
      cacheUserData(userData);

   }).then( (userData) -> {
      // it should be called after all previous operations completed
      displayUserData()

   }).doOnError( (error) -> {
      //do something
   })

J'ai trouvé cette bibliothèque très intéressante, mais je n'arrive pas à comprendre comment enchaîner les demandes là où les autres dépendent des précédentes.

42
Mikhail

Bien sûr, RxJava prend en charge .map qui fait cela. Depuis le wiki RxJava:

map

Fondamentalement, ce serait:

loginObservable()
   .switchMap( someData -> fetchUserDataObservable(someData) )
   .map( userData -> cacheUserData(userData) )
   .subscribe(new Subscriber<YourResult>() {
        @Override
        public void onCompleted() {
           // observable stream has ended - no more logins possible
        }
        @Override
        public void onError(Throwable e) {
            // do something
        }
        @Override
        public void onNext(YourType yourType) {
            displayUserData();
        }
    });
41
Benjamin Gruenbaum

Ceci est le premier message lorsque Googling Observables de la chaîne RxJava donc je vais juste ajouter un autre cas courant où vous ne voudriez pas transformer les données que vous recevez, mais enchaînez-le avec une autre action (définir les données dans une base de données, par exemple). Utilisez .flatmap(). Voici un exemple

    mDataManager.fetchQuotesFromApi(limit)
            .subscribeOn(mSchedulerProvider.io())
            .observeOn(mSchedulerProvider.ui())
            .onErrorResumeNext(Function { Observable.error<List<Quote>>(it) }) //OnErrorResumeNext and Observable.error() would propagate the error to the next level. So, whatever error occurs here, would get passed to onError() on the UI side
            .flatMap { t: List<Quote> ->
                //Chain observable as such
                mDataManager.setQuotesToDb(t).subscribe({}, { e { "setQuotesToDb() error occurred: ${it.localizedMessage}" } }, { d { "Done server set" } })
                Observable.just(t)
            }
            .subscribeBy(
                    onNext = {},
                    onError = { mvpView?.showError("No internet connection") },
                    onComplete = { d { "onComplete(): done with fetching quotes from api" } }
            )

C'est RxKotlin2, mais l'idée est la même avec RxJava & RxJava2:

Explication rapide:

  • nous essayons de récupérer des données (guillemets dans cet exemple) à partir d'une API avec mDataManager.fetchQuotesFromApi()
  • Nous souscrivons l'observable pour faire des choses sur le thread .io() et afficher les résultats sur le thread .ui().
  • onErrorResumeNext() s'assure que toute erreur rencontrée lors de la récupération des données est détectée dans cette méthode. Je veux terminer la chaîne entière quand il y a une erreur, donc je retourne une Observable.error()
  • .flatmap() est la partie de chaînage. Je veux pouvoir définir toutes les données que j'obtiens de l'API dans ma base de données. Je ne transforme pas les données que j'ai reçues en utilisant .map(), je fais simplement autre chose avec ces données sans le transformant.
  • Je souscris à la dernière chaîne d'observables. Si une erreur se produisait lors de la récupération des données (première observable), elle serait gérée (dans ce cas, propagée à la onError()) abonnée avec onErrorResumeNext()
  • Je suis très conscient que je m'abonne à la DB observable (à l'intérieur de flatmap()). Toute erreur qui se produit à travers cette observable sera [~ # ~] pas [~ # ~] propagée aux dernières méthodes subscribeBy() , car il est géré à l'intérieur de la méthode subscribe() à l'intérieur de la chaîne .flatmap().

Le code provient de ce projet qui se trouve ici: https://github.com/Obaied/Sohan/blob/master/app/src/main/Java/com/obaied/ dingerquotes/ui/start/StartPresenter.kt

8
Solidak

essayez d'utiliser scan ()

Flowable.fromArray(array).scan(...).subscribe(...)
0
lingfliu