RxJava2. Выполнить запрос для каждого элемента в списке

У меня есть список List<FileModel>

FileModel - это просто класс, содержащий id: Int

id - это идентификатор файла фотографии, который мне нужно получить и передать в Bitmap.

У меня есть запрос:

fun getFile(fileId: Int): Single<ResponseBody>

Этот запрос возвращает ResponseBody, который мы можем преобразовать в Bitmap.

И

fun generatePhoto(responseBody: ResponseBody): Single<Bitmap?>

Я хочу создать функцию

fun getPhotos(list: List<FileModel>): Single<List<Bitmap>> {
    // Execute getFile(...) for each item in the list
    // Cast getFile(...) result to Bitmap using generatePhoto(...)
    // Return a list of Bitmaps
}

Я пробовал что-то подобное, но это совершенно не так

fun getPhotos(list: List<FileModel>): Single<List<Bitmap>> {
    return Observable.fromIterable(list)
        .flatMap { getFile(it.id) }
        // How to call generatePhoto(...) here?
}

person xskit    schedule 11.05.2018    source источник
comment
Я не эксперт в Rx, не могли бы вы привести пример?   -  person xskit    schedule 11.05.2018
comment
На самом деле, это, вероятно, просто должна быть flatMap.   -  person EpicPandaForce    schedule 11.05.2018


Ответы (3)


Сделать это можно так:

fun getPhotos(list: List<FileModel>): Single<List<Bitmap>> {
    // Get an Observable of the list
    return Observable.fromIterable(list)
        // Get a Single<ResponseBody> for every FileModel
        .flatMapSingle { getFile(it.id) }
        // Get a Single<Bitmap> for every ResponseBody
        .flatMapSingle { file -> generatePhoto(file) }
        // Put everything back on a list
        .toList()
}

Таким образом, вы можете перебирать список flapMapping в соответствии с вашими потребностями, а затем снова собрать его в виде списка в конце. Оператор toList() - это просто удобство, которое объединяет элементы, созданные ранее.

И чтобы вызвать эту функцию, просто выполните:

    getPhotos(list)
        .doOnSuccess { resultList ->
          Log.d("Rx", "doOnSuccess.resultList=[$resultList]")
        }
        .subscribe()

Кстати, если у вас RxKotlin в качестве зависимости, вы можете получить Observable от List с функцией расширения, например: myList.toObservable()

person Rodrigo Direito    schedule 11.05.2018
comment
Спасибо за ответ. - person xskit; 14.05.2018

Observable.fromIterable (list) должен генерировать событие для каждого элемента в списке, что означает, что ваш тип возвращаемого значения в getPhotos будет Flowable<Bitmap>, поскольку Flowable может возвращать более одного значения.

Я думаю, что на самом деле вам нужно:

fun getPhotos(list: List<FileModel>): Flowable<Bitmap> {
    return Observable.fromIterable(list)
        .map { getFile(it.id) }
        .map { generatePhoto(it) }
}

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

fun getPhotos(list: List<FileModel>): Single<List<Bitmap>> {
    return Single.just(list)
        .map { it.map { getFile(it.id) } }
        .flatMap { 
            Single.just(it.map { generatePhoto(it) }) 
        }
}
person Stevenkang90    schedule 11.05.2018
comment
Но если мы используем Single.just (список) внутри карты {}, у нас будет List ‹FileModel› вместо FileModel. - person xskit; 11.05.2018
comment
Я обновил ответ, вы можете перебирать каждый список внутри блока карты - person Stevenkang90; 11.05.2018
comment
вы можете использовать flatMap для оценки сингла, но в этом случае вам нужно создать еще один сингл - person Stevenkang90; 11.05.2018
comment
Спасибо за ответ. - person xskit; 14.05.2018

Ты пытался:

fun getPhotos(list: List<FileModel>): Single<List<Bitmap>> {
    return Observable.fromIterable(list)
        .flatMapSingle { getFile(it.id) }
        .flatMapSingle { generatePhoto(it) }
}

?

person EpicPandaForce    schedule 11.05.2018
comment
Мы не можем вызвать flatMapSingle после flatMap - person xskit; 11.05.2018
comment
Вы правы, может быть flatMapSingle должно быть на обоих. - person EpicPandaForce; 11.05.2018
comment
Спасибо за ответ. - person xskit; 14.05.2018