FlatMap失败后,RxJava在totalMap失败后使用toList

时间:2018-11-15 16:43:29

标签: android kotlin rx-java rx-java2

我有三个对象(例如A,B,C),要获取CI,需要B,要获取A,我需要B。在屏幕中,我需要同时显示A的属性和C的属性。我可以获取所有必要的数据,因为我使用的是不带onComplete的flatMap,因此不会执行toList()。这是我的代码。

对于列表中的每个a,我需要获取c,并且需要返回ResultMode类型的列表,其中包括a和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()
    }

注意:我今天早些时候问过类似的问题,但并不需要多次使用平面图。您可以在此链接中查看我的解决方案

RxJava - Mapping a result of list to another list

我的努力(可能错了) 这是我转换第一种方法的工作(对于第二种方法,我只是将其删除为Flowable并返回单一方法),但是还有很长的路要走,我认为我走错了路。

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

2 个答案:

答案 0 :(得分:1)

编辑:我找到了另一个解决方案

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

原始解决方案

这是我的解决方案,但我认为该解决方案确实很杂乱,可以进行很多改进。

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

答案 1 :(得分:1)

似乎没有必要不断地解构和重建列表。假设没有:

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

由于concatMapSingle()运算符知道每个项目,因此在构造ResultModel时可以知道其名称。现在,您不再需要如此频繁地撕碎东西。