RxJava - extraire chaque élément de la liste

j'ai une méthode qui renvoie un Observable<ArrayList<Long>>, qui sont des ID de certains articles. Je voudrais passer en revue cette liste et télécharger chaque élément en utilisant une autre méthode qui retourne Observable<Item>.

Comment faire avec les opérateurs RxJava?

26
demandé sur Austyn Mahoney 2015-01-20 02:08:03

4 réponses

voici un petit exemple indépendant

public class Example {

    public static class Item {
        int id;
    }

    public static void main(String[] args) {
        getIds()
                .flatMapIterable(ids -> ids) // Converts your list of ids into an Observable which emits every item in the list
                .flatMap(Example::getItemObservable) // Calls the method which returns a new Observable<Item>
                .subscribe(item -> System.out.println("item: " + item.id));
    }

    // Simple representation of getting your ids.
    // Replace the content of this method with yours
    private static Observable<List<Integer>> getIds() {
        return Observable.just(Arrays.<Integer>asList(1, 2, 3));
    }

    // Replace the content of this method with yours
    private static Observable<Item> getItemObservable(Integer id) {
        Item item = new Item();
        item.id = id;
        return Observable.just(item);
    }
}

Veuillez noter que Observable.just(Arrays.<Integer>asList(1, 2, 3)) est une simple représentation de Observable<ArrayList<Long>> de votre question. Vous pouvez le remplacer par votre propre Observable dans votre code.

Cela devrait vous donner la base de ce que vous avez besoin.

p/s : Utiliser flatMapIterable méthode pour ce cas puisqu'il appartient à Iterable comme ci-dessous expliquant:

/**
 * Implementing this interface allows an object to be the target of
 * the "for-each loop" statement. See
 * <strong>
 * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides /language/foreach.html">For-each Loop</a>
 * </strong>
 *
 * @param <T> the type of elements returned by the iterator
 *
 * @since 1.5
 * @jls 14.14.2 The enhanced for statement
  */
 public interface Iterable<T>
42
répondu Miguel Lavigne 2017-05-12 07:58:13

un Transformateur qui modifie la source Observable, appelant un flatMap avec une fonction. Vous pouvez voir cela comme un processus en deux étapes:

  1. la fonction prend chaque élément émis (un Iterable<T>) et le réémet comme un Observable<T>
  2. flatMap prend chacune de ces émissions Observable<T> objets un les fusionne en un seul Observable<T>

Le Transformateur ressemble à ceci:

public class FlattenTransform<T> implements Observable.Transformer<Iterable<T>, T> {
    @Override
    public Observable<? extends T> call(Observable<? extends Iterable<T>> source) {
        return source.flatMap(new Func1<Iterable<T>, Observable<T>>() {
            @Override
            public Observable<T> call(Iterable<T> values) {
                return Observable.from(values);
            }
        });
    }
}

une Fois que vous avez créé votre Transformateur, vous pouvez utiliser compose pour appliquer la transformation de la source de l'observable:

public class Example {

    private static final ArrayList<Long> sourceList = new ArrayList<>(Arrays.asList(new Long[] {1L,2L,3L}));
    private static final Observable<ArrayList<Long>> listObservable = Observable.just(sourceList);
    private static final FlattenTransform<Long> flattenList = new FlattenTransform<Long>();

    public static void main(String[] args) {
        listObservable.compose(flattenList).subscribe(printItem);
    }

    private static Action1<Long> printItem = new Action1<Long>() {
        @Override
        public void call(Long item) {
            System.out.println("item: " + item);
        }
    };
}

L'avantage de l'utilisation d'un compose avec un Transformer au lieu d'un flatMap avec un Func1 est-ce que si dans le futur si vous avez besoin d'aplatir une liste à nouveau, vous n'aurez même pas à penser à quel opérateur utiliser (map? flatMap? concatMap?). En d'autres termes, l'opération flatmap est cuite dans la classe FlattenTransform et ce détail est résumé loin.

les transformateurs ont aussi d'autres avantages, comme la possibilité de enchaîner plusieurs opérations.

4
répondu weefbellington 2015-04-07 18:56:06

comme alternative à flatMapIterable vous pouvez le faire avec flatMap:

Observable.just(Arrays.asList(1, 2, 3)) //we create an Observable that emits a single array
            .flatMap(numberList -> Observable.fromIterable(numberList)) //map the list to an Observable that emits every item as an observable
            .flatMap(number -> downloadFoo(number)) //download smth on every number in the array
            .subscribe(...);


private ObservableSource<? extends Integer> downloadFoo(Integer number) {
   //TODO
}

Personnellement, je pense que .flatMap(numberList -> Observable.fromIterable(numberList)) est plus facile à lire et à comprendre que les .flatMapIterable(numberList -> numberList ).

la différence semble être l'ordre (RxJava2):

  • Observables.fromIterable: Convertit une séquence itérable en une source observable qui émet les éléments de la séquence.
  • Observables.flatMapIterable: Retourne un Observable qui fusionne chaque élément émis par la source ObservableSource avec les valeurs dans une itération correspondant à cet élément qui est généré par un sélecteur.

Utilisation de la méthode des références, cela ressemble à:

Observable.just(Arrays.asList(1, 2, 3))
            .flatMap(Observable::fromIterable)
            .flatMap(this::downloadFoo)
3
répondu for3st 2017-06-07 16:17:10

à Kotlin utiliserflattenAsFlowable:

repository.getFlowableData(id)
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.computation())
    .toList()
    .flattenAsFlowable { it }
    .map { someMethod(it) }
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ },
        { onError(it) })
1
répondu CoolMind 2018-06-13 12:08:51