2015-01-19 19 views
22

Mam metodę zwracającą wartość Observable<ArrayList<Long>>, która jest identyfikatorem niektórych elementów. Chciałbym przejrzeć tę listę i pobrać każdy element przy użyciu innej metody, która zwraca Observable<Item>.RxJava - pobierz każdy element z listy

Jak to zrobić, używając operatorów RxJava?

+0

nakazuje ważne? – lopar

+0

Niezupełnie, ale dla celów edukacyjnych naprawdę lubię widzieć obie wersje: –

Odpowiedz

38

Oto mały autonomiczny przykład

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

Uwaga Observable.just(Arrays.<Integer>asList(1, 2, 3)) jest prostym przedstawieniem Observable<ArrayList<Long>> z Twoim pytaniem. Możesz go zastąpić własnym obserwowalnym w swoim kodzie.

To powinno dać ci podstawę tego, czego potrzebujesz.

p/s: Wykorzystanie flatMapIterable metoda dla tej sprawy, ponieważ należy do Iterable jak poniżej wyjaśniając:

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

Można również zrobić Observable.from (Arrayys. asList (...)) i nie potrzebować flatMapIterable – lopar

+0

Dzięki, zadziałało! –

+0

Uratowałeś mi życie. Dzięki. –

3

Użyj Transformer który modyfikuje źródło obserwowalne, nazywając się flatMap na nim z funkcji. Można myśleć o tym jako o procesie 2-etapowym:

  1. Funkcja przyjmuje każdą emitowanego element (Iterable<T>) i ponownie emituje go jako Observable<T>
  2. flatMap zajmuje każda z tych emitowanego Observable<T> obiektów je łączy w jeden Observable<T>

Transformer wygląda następująco:

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

Po utworzeniu Transformer, można użyć compose zastosować transformację od źródła do zaobserwowania:

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

Zaletą korzystania z compose z Transformer zamiast flatMap z Func1 jest to, że jeśli w przyszłość, jeśli chcesz ponownie spłaszczyć listę, nie musisz nawet myśleć o tym, którego operatora użyć (mapa? flatMap? concatMap?). Innymi słowy, operacja na mapie liniowej jest wypalana w klasie FlattenTransform i ten szczegół jest usuwany.

Transformatory mają również inne zalety, takie jak możliwość łączenia wielu operacji.

1

Jako alternatywę dla flatMapIterable można to zrobić z 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 
} 

Osobiście myślę .flatMap(numberList -> Observable.fromIterable(numberList)) jest łatwiejsze do odczytania i zrozumienia niż .flatMapIterable(numberList -> numberList).

Różnica wydaje się być rzędu (RxJava2)

  • Observable.fromIterable: Przekształca Iterable sekwencję do ObservableSource emitującego elementów w sekwencji.
  • Observable.flatMapIterable: Zwraca obserwowalne, które łączy każdy element emitowany przez źródło ObservableSource z wartościami w Iterable odpowiadającymi temu elementowi, który jest generowany przez selektor.

Korzystanie referencje Metoda ta wygląda następująco:

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

Proszę spojrzeć na to pytanie: https://stackoverflow.com/questions/ 48959354/how-to-convert-from-observablelistx-to-observablelisty-using-a function –