Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxJava2. Execute a request for every item in a list

I have a list List<FileModel>

FileModel is just a class contains id: Int

id - is ID of photo file I need to fetch and cast to Bitmap

I have a request:

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

This request returns ResponseBody which we can cast to Bitmap

And

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

What I want is to create a function

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
}

I've tried something like this but it's completely wrong

fun getPhotos(list: List<FileModel>): Single<List<Bitmap>> {
    return Observable.fromIterable(list)
        .flatMap { getFile(it.id) }
        // How to call generatePhoto(...) here?
}
like image 582
xskit Avatar asked May 11 '18 13:05

xskit


2 Answers

You can do it like this:

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

This way you can iterate over the list flapMapping for your needs and then putting it back together as a list in the end. The toList() operator is just a convenience that puts together the items emitted previously.

And to call this function just go:

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

By the way, if you have RxKotlin as a dependency you can get an Observable from a List with an extension function, like this: myList.toObservable()

like image 62
Rodrigo Direito Avatar answered Sep 26 '22 10:09

Rodrigo Direito


Observable.fromIterable(list) should emit an event for each item in the list which means that you're return type in getPhotos be Flowable<Bitmap> as Flowable can return more than one value.

I think what you actually want is:

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

if you want to emit a list of Bitmaps you can use single like this

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) }) 
        }
}
like image 37
Stevenkang90 Avatar answered Sep 24 '22 10:09

Stevenkang90