2015-01-19 11 views
22

Ich habe eine Methode, die eine Observable<ArrayList<Long>> zurückgibt, die Ids einiger Items sind. Ich möchte diese Liste durchgehen und alle Elemente mit einer anderen Methode herunterladen, die Observable<Item> zurückgibt.RxJava - holen Sie jedes Element auf der Liste

Wie würde ich dies mit RxJava-Operatoren tun?

+0

wichtig ist, bestellen? – lopar

+0

Nicht wirklich, aber für Bildungszwecke ist wirklich beide Versionen zu sehen –

Antwort

38

Hier ist eine kleine in sich geschlossene Beispiel

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); 
    } 
} 

Bitte beachten Sie, dass Observable.just(Arrays.<Integer>asList(1, 2, 3)) eine einfache Darstellung von Observable<ArrayList<Long>> aus Ihrer Frage ist. Sie können es durch Ihr eigenes Observable in Ihrem Code ersetzen.

Dies sollte Ihnen die Grundlage dafür geben, was Sie brauchen.

p/s: Verwenden flatMapIterable Methode für diesen Fall, da es zu Iterable wie unten erklärt, gehört:

/** 
* 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> 
+1

Sie könnten auch Observable.from (Arrays. asList (...)) und nicht brauchen die FlatMapIterable – lopar

+0

Danke, es hat funktioniert! –

+0

Du hast mein Leben gerettet. Vielen Dank. –

3

Verwenden Sie ein Transformer, die die Quelle beobachtbare modifiziert, eine flatMap auf sie mit einer Funktion aufrufen. Sie können als 2-Stufen-Prozess daran denken:

  1. Die Funktion nimmt jede emittierte Punkt (ein Iterable<T>) und erneut emittiert es als Observable<T>
  2. flatMap nimmt jede dieser emittierten Observable<T> Objekte ein, sie verschmilzt in eine einzige Observable<T>

Der Transformator sieht wie folgt aus:

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); 
      } 
     }); 
    } 
} 

Nachdem Sie Ihre Transformer erstellt haben, können Sie compose verwenden, um die Transformation auf der Quelle beobachtbaren anwenden:

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); 
     } 
    }; 
} 

Der von Vorteil, eine compose mit einem Transformer anstelle eines flatMap mit einem Func1 ist, dass, wenn in der Zukunft, wenn Sie eine Liste wieder flattern müssen, müssen Sie nicht einmal darüber nachdenken, welcher Operator zu verwenden ist (Karte? FlacheKarte? concatMap?). Mit anderen Worten, die Flatmap-Operation wird in die FlattenTransform-Klasse eingebettet, und dieses Detail wird abstrahiert.

Transformatoren haben auch andere Vorteile, z. B. in der Lage, mehrere Operationen zu verketten.

1

Als Alternative zu flatMapIterable Sie dies mit flatMap tun können:

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 
} 

Ich persönlich denke, .flatMap(numberList -> Observable.fromIterable(numberList)) leichter ist als .flatMapIterable(numberList -> numberList) zu lesen und zu verstehen.

Der Unterschied scheint die Reihenfolge (RxJava2) zu sein:

  • Observable.fromIterable: Wandelt eine Iterable Sequenz in eine ObservableSource, die die Elemente in der Folge aussendet.
  • Observable.flatMapIterable: Gibt ein Observable zurück, das jedes von der Quelle ObservableSource ausgegebene Element mit den Werten in einem Iterable zusammenführt, das dem Element entspricht, das von einem Selektor generiert wird.

Unter Verwendung der Methode Referenzen dies wie folgt aussieht:

Observable.just(Arrays.asList(1, 2, 3)) 
      .flatMap(Observable::fromIterable) 
      .flatMap(this::downloadFoo) 
+0

Bitte werfen Sie einen Blick auf diese Frage: https://stackoverflow.com/questions/ 48959354/how-to-convert-from-observable-listx-zu-observable-listy-using-a-function –

Verwandte Themen