RxJava: как преобразовать один в один <Список>

#android #kotlin #lambda #repository #rx-java

#Android #kotlin #лямбда #репозиторий #rx-java

Вопрос:

Допустим, у меня есть приложение для Android со следующим классом репозитория для извлечения объектов из API:

 override fun fetchOrderById(orderId: Long): Single<List<ItemRow>> {
    return api.fetchOrderByIdObservable(orderId)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .map { orderResponse ->
                orderResponse.items.map { deliveryItem ->
                    deliveryItem.asItemRow()
                }
            }
}

override fun fetchOrders(): Single<OrdersResponse> {
    return api.fetchOrdersObservable()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
}

override fun fetchAllOrders(): Single<List<ItemRow>> {
     // TODO
}
  

Со следующим классом данных:

 class OrdersResponse(@SerializedName("orders") val orders: List<Long>)
class OrderResponse(@SerializedName("items") val items: List<DeliveryItem>)
  

Прямо сейчас я могу использовать fetchOrderById, чтобы получить все элементы доставки (ItemRow) для определенного OrderID в качестве объекта домена в моем приложении для отображения в списке. Как я могу использовать fetchOrders , который возвращает список идентификаторов заказов, чтобы получить все элементы доставки для всех заказов? Какие операторы были бы полезны здесь? Я поиграл с flatMap, но не смог заставить его работать. Ссылка на статьи тоже будет . Спасибо!

Ответ №1:

нужные вам операторы: switchMap() , flatMap() , fromArray() , toList() , map() это будет что-то вроде этого:

 fun fetchAllOrders(): Observable<List<ItemRow>> {
    return fetchOrders()
        .toObservable()
        .switchMap { ordersResponse ->
            Observable.fromIterable(ordersResponse.orders)
                .flatMap {orderId -> fetchOrderById(orderId).toObservable() }
                .toList()
                .toObservable()
        }
        .map { list -> list.flatten() }
    }
  

Комментарии:

1. Хммм, спасибо за ответ, но этот не работает. В . flatMap {orderId -> fetchOrderById(orderId) } передается список <Длинный> (список идентификаторов порядка), а не длинный (идентификатор порядка)! :/

2. @sorry_I_wont произошла ошибка опечатки, пожалуйста, смотрите Отредактированный ответ. Вам нужно перейти ordersResponse.orders в Observable.fromArray

3. Я не думаю, что проблема в опечатке, у меня эта ошибка в теле switchMap: Type mismatch. Required: ObservableSource<out (???..???)>! Found: Single<(Mutable)List<List<ItemRow>!>!>! Type mismatch. Required: ObservableSource<out TypeVariable(R)!>! Found: Single<(Mutable)List<List<ItemRow>!>!>!

4. Отредактировано снова, добавьте .toObservable() после fetchOrders()

5. Спасибо, на этот раз он скомпилирован! Это странно, в чем разница между «вызовом ToObservable для fetchOrders()» и «если fetchOrders() возвращает наблюдаемое вместо одного»? Потому что, когда я меняю его на fetchOrders(), чтобы возвращать наблюдаемый <OrdersResponse> вместо Single , это не сработает, но они должны быть одинаковыми!!

Ответ №2:

В конечном итоге это сработало:

     public fun fetchAllItems(): Observable<List<ItemRow>> {
    return networkService.api.fetchOrdersObservable()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .flatMap { orderResponse ->  Observable.just(orderResponse.orders) }
            .flatMapIterable { id -> id }
            .flatMap { id -> fetchOrderById(id) }
            .flatMapIterable { itemRow -> itemRow }
            .toList()
}