简体   繁体   中英

RxJava using toList after flatMap fails as flatMap isn't complete

I have three objects (say A,B,C) and to get CI need B, and to get A, I need B. In screen I need to display a property of A together with a property of C. Even though I can get all necessary data, since I use flatMap which do not have onComplete, toList() does not get executed. Here is my code.

For every a in List I need to get c and I need to return a list of type ResultMode which includes properties of a and c.

override fun methodICall(): LiveData<MutableList<ResultModel>> {
        return mySdk
                .getAllA() //Returns Flowable<List<A>>
                .flatMap { Flowable.fromIterable(it) }
                .flatMap { helperMethod(it) }
                .toList() // Does not get executed as flatMap isnt completed
                .toFlowable()
                .onErrorReturn { Collections.emptyList() }
                .subscribeOn(Schedulers.io())
                .to { LiveDataReactiveStreams.fromPublisher(it) }
    }

    private fun helperMethod(a:A): Flowable<ResultModel> {
        return mySdk
                .getB(a.propertyOne!!) // Returns Single<B>
                .flatMap { mySdk.getC(it.property!!) } // get C returns Single<C>
                .map {
                    ResultModel(name= a.name,
                            date = c.date.toString(), 
                            message = it.messageId!!
                         )
                }.toFlowable()
    }

Note: I asked a similar question earlier today but it did not require using flatmap more than once. You can view my solution to that in this link

RxJava - Mapping a result of list to another list

My Effort (Which is probably wrong) Here is my effort of transforming first method (for second method I just remove to Flowable and return single) but it has a long way to go and I think I am in the wrong path.

 override fun methodICall(): LiveData<MutableList<ResultModel>> {
        return mySdk
                .getAllA()
                .concatMapSingle { Flowable.fromIterable(it)
                        .map { helperMethod(it) }
                        .toList()
                }
                .onErrorReturn { Collections.emptyList() }
                .subscribeOn(Schedulers.io())
                .to { LiveDataReactiveStreams.fromPublisher(it) // here it is single. I think it is because two maps are applied both to helperMethod itself and inside helper method to result model}
    }

Edit : I found another solution

 override fun methodICall(): LiveData<MutableList<ResultModel>> {
        return mySdk
                .getAllA()
                .concatMapSingle {
                    Flowable.fromIterable(it)
                            .flatMap { a ->
                                mySdk.getB(a.propertyOfA!!)
                                        .flatMap { b -> chatbotSdk.getC(b.propertyOfB!!) }
                                        .map { it ->

                                            ResultModel(name = a.name,
              message = it.body!!)
              }.toFlowable() 
                            } .toList()    }
                .onErrorReturn { Collections.emptyList() }
                .subscribeOn(Schedulers.io())
                .to { LiveDataReactiveStreams.fromPublisher(it) }
    }

Original Solution

This is my solution but I think this solution is really messy and it can be improved a lot.

  data class AtoBDTO(var name: String, var b: Flowable<B>) // I wanted to map one object to more than one so I created this. Probably there is a way to do it with rx functions.
    data class BtoCDTO(var name: String, var c: Flowable<C>)



    override fun methodICall(): LiveData<MutableList<ResultModel>> {
            return mySdk
                    .getAllA() // Returns Flowable<List<A>>
                    .concatMapSingle {
                        Flowable.fromIterable(it)
                                .map { AtoBDTO(it.name!!,    
 mySdk.getB(it.propertyOfA!!).toFlowable()) }  //getB returns Single B
                                .toList()
                    }
                    .concatMapSingle {
                        Flowable.fromIterable(it)
                                .map {
                                    BtoCDTO(it.name,
                                            it.b.concatMapSingle { mySdk.getC(it.propertyOfB!!) }) // getC returns Single C
                                }
                                .toList()
                    }
                    .concatMapSingle {
                        Flowable.fromIterable(it)
                                .map {
                                    ResultModel(name = it.name,
                                            message = it.c.blockingFirst().body!!) // I use blocking first because otherwise I can't get rid of flowable
                                }.toList()
                    }
                    .onErrorReturn { Collections.emptyList() }
                    .subscribeOn(Schedulers.io())
                    .to { LiveDataReactiveStreams.fromPublisher(it) }
        }

There doesn't seem to be a good reason to continually deconstruct and reconstruct lists. Assuming there isn't:

override fun methodICall(): LiveData<MutableList<ResultModel>> {
        return mySdk
                .getAllA() // Returns Flowable<List<A>>
                .flatMapIterable(it)
                .concatMapSingle( item => {
                  mySdk.getB(item.propertyOfA!!)
                    .flatMap( bItem => mySdk.getC( bItem.propertyOfB!! ) )
                    .map( ResultModel( name=item.name, message=it.body!! ) )
                 })
                .toList()
                .onErrorReturn { Collections.emptyList() }
                .subscribeOn(Schedulers.io())
                .to { LiveDataReactiveStreams.fromPublisher(it) }
    }

Because the concatMapSingle() operator knows about each item, its name can be known when it is time to construct the ResultModel . Now, you no longer need to tear things apart so often.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM