Как объединить несколько вызовов API для создания единого объекта ответа с использованием RxJava - PullRequest
0 голосов
/ 08 октября 2019

Я создаю приложение, которое состоит из двух вызовов API. Я все еще изучаю RxJava, и я не уверен, как правильно объединить два вызова API

  1. Первый вызов API используется для извлечения элементов в виде списка
  2. . Второй вызов API используется для получения изображения элемента, используя имя элемента, полученное при первом вызове.

Мне нужно показать все элементы с их изображениями. Это мои вызовы API, использующие модификацию

@GET("items/list")
fun getItems(): Observable<ItemResult>

@GET("item/{name}/images")
fun getItemDetails(@Path("name") name: String): Observable<ItemDetails>

Это код, написанный с помощью RxJava:

    fun getItemsData(): Observable<ArrayList<ItemDetails>> {

    val data = ArrayList<ItemDetails>()
getItems().flatMap { itemResponse -> Observable.just(itemResponse.message) } //this will give me a list with item names
        .flatMapIterable { data -> data }//iterating over the list and for every item...
        .map { itemName ->//calling to get the item image
            getItemDetails(itemName).map { imageData ->
                val itemImage = imageData.message
                data.add(ItemData(itemName, itemImage))//from this point on I'm lost, I'm not sure if it's the right thing to add here the data
            }.subscribeOn(Schedulers.io())
        }.subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())

    return Observable.create(data)// not sure how to create an Observable from the data
}   

Ответы [ 4 ]

0 голосов
/ 09 октября 2019

Вам это на самом деле не нужно ...

val data = ArrayList<ItemDetails>()

flatMap - неправильный оператор здесь:

flatMap { itemResponse -> Observable.just(itemResponse.message) }

вы можете упростить это с помощью mapвместо этого (функция itemResponse -> itemResponse.message работает только с внутренним значением).

map { itemResponse -> itemResponse.message }

Далее:

.flatMapIterable { data -> data } // here we have Observable<Message>
.flatMap { itemName ->
     getItemDetails(itemName).map { imageData ->
        ItemData(itemName, imageData)
     }
 } // Observable<ItemData>
.toList() // Single<List<ItemData>> -> you can use toObservable to get an Observable<List<ItemData>>

Вы можете использовать toList() вместо того, чтобы вручную создавать и заполнять ArrayList, это упрощает вещи.

0 голосов
/ 09 октября 2019

Вы не подписаны на внутренний поток внутри карты. Попробуйте это:

val data = ArrayList<ItemDetails>()
    getItems().flatMap { itemResponse -> Observable.just(itemResponse.message) } //this will give me a list with item names
            .flatMapIterable { data -> data }//iterating over the list and for every item...
            .flatmap(itemName -> getItemDetails(itemName).subscribeOn(Schedulers.io())
            .map(itemDetail -> {//add to the list)})
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())

    return Observable.fromIterable(data);
0 голосов
/ 09 октября 2019

Если вы действительно хотите вернуть Observable<ArrayList<ItemDetails>>, возможно, вы могли бы использовать reduce?

Примерно так:

fun getItemsData(): Observable<ArrayList<ItemDetails>> {
   return
     getItems().flatMap { itemResponse -> Observable.just(itemResponse.message) }
               .flatMapIterable { data -> data }
               .flatMap { itemName -> getItemDetails(itemName)  }.subscribeOn(Schedulers.io())
               .map { imageData -> ItemData(itemName, imageData.message) } }
               .reduce(ArrayList<ItemDetails>(), (list, item) -> list.add(item))
               .toObservable()   
               .subscribeOn(Schedulers.io())
               .observeOn(AndroidSchedulers.mainThread())
}

Я не уверен в правильном синтаксисеreduce в Котлине ...

0 голосов
/ 09 октября 2019

Вам необходимо отобразить поток с плоским отображением, чтобы получить нужный тип -

getItems()
.flatMap(item -> getItemDetails(item)
                 .map(itemDetail -> ItemData(item, itemDetail.image))
.subscribe(itemData -> // your desired type containing the original item and image);
...