tutorial rxjava example java monads reactive-programming rx-java

example - rxjava tutorial



RxJava-busca todos los elementos de la lista (4)

Tengo un método que devuelve un Observable<ArrayList<Long>> , que son identificadores de algunos artículos. Me gustaría revisar esta lista y descargar todos los elementos utilizando otro método que devuelve Observable<Item> .

¿Cómo haría esto usando operadores RxJava?


Aquí hay un pequeño ejemplo autocontenido.

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

Tenga en cuenta que Observable.just(Arrays.<Integer>asList(1, 2, 3)) es una representación simple de Observable<ArrayList<Long>> de su pregunta. Puedes reemplazarlo con tu propio Observable en tu código.

Esto debería darle la base de lo que necesita.

p / s: Utilice el método flatMapIterable para este caso, ya que pertenece a Iterable como se explica a continuación:

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


Como alternativa a flatMapIterable , puede hacer esto con 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 }

Personalmente creo que .flatMap(numberList -> Observable.fromIterable(numberList)) es más fácil de leer y entender que .flatMapIterable(numberList -> numberList ) .

La diferencia parece ser el orden (RxJava2):

  • Observable.fromIterable: convierte una secuencia iterable en una fuente observable que emite los elementos en la secuencia.
  • Observable.flatMapIterable: devuelve un Observable que combina cada elemento emitido por la fuente ObservableSource con los valores en un Iterable correspondiente a ese elemento generado por un selector.

Usando referencias de métodos, esto se ve así:

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


En Kotlin use flattenAsFlowable :

repository.getFlowableData(id) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .toList() .flattenAsFlowable { it } .map { someMethod(it) } .observeOn(AndroidSchedulers.mainThread()) .subscribe({ }, { onError(it) })


Utilice un Transformer que modifique la fuente observable, invocando un flatMap en él con una función. Puedes pensar en esto como un proceso de 2 pasos:

  1. La función toma cada elemento emitido (un Iterable<T> ) y lo vuelve a emitir como un Observable<T>
  2. flatMap toma cada uno de estos objetos Observable<T> emitidos y los combina en un solo Observable<T>

El transformador se ve así:

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

Una vez que haya creado su Transformador, puede usar compose para aplicar la transformación en la fuente 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); } }; }

La ventaja de usar una compose con un Transformer lugar de un flatMap con un Func1 es que si en el futuro, si necesita aplanar una lista de nuevo, ni siquiera tendrá que pensar qué operador usar (map? FlatMap? ConcatMap ?). En otras palabras, la operación de mapa plano se integra en la clase FlattenTransform y ese detalle se extrae.

Los transformadores también tienen otros beneficios, como poder encadenar varias operaciones.