Reputation: 158
I have three objects (say A,B,C) and to get C I 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}
}
Upvotes: 1
Views: 1483
Reputation: 158
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) }
}
Upvotes: 1
Reputation: 8227
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.
Upvotes: 1