在Kotlin中使用Flowable的多个改进2请求

为了提高我在kotlin,Rx,Retrofit2方面的技能,我决定做一个演示项目。 演示项目包括在回收站视图中显示帖子,然后在详细活动中显示帖子的详细信息。
我遇到了显示来自不同API调用的数据的困难:用户名,标题,帖子正文以及帖子的评论数量。

我的问题是,我想要做多个请求,然后获取所需的所有数据,以便在详细的活动中显示它们。 这意味着做一个电话,给我的用户名,然后打电话给我的帖子的评论数。 帖子的标题和正文来自于主要活动中的一个请求,我只是把它传递给详细的活动。

Api调用:
//返回帖子的评论1
http://jsonplaceholder.typicode.com/comments?postId=1

//返回用户2的信息
http://jsonplaceholder.typicode.com/users/2

//调用用于显示主要活动中的帖子
HTTP:/jsonplaceholder.typicode.com/posts

我还是Rx上的新手,我正在考虑使用flatMap,但我不知道如何在kotlin中使用Flowable。

var post = viewModel.getPost() var userStream: Flowable<User> = postService.getUser(post.userId) var commentsByPostIdCall: Flowable<List<Comment>> = postService.getCommentsByPostId(post.id) userStream.subscribeOn(Schedulers.io()) .subscribe(object : Subscriber<User> { override fun onError(t: Throwable?) { Log.d(this.toString(), " Read of users failed with the following message: " + t?.message); } override fun onNext(user: User) { userTextView.text = user.name title.text = post.title body.text = post.body } override fun onComplete() { } override fun onSubscribe(s: Subscription?) { if (s != null) { s.request(1) } } }) 

我已经把第二个调用放在方法getNumberComments中

  private fun getNumberComments(commentsByPostIdCall: Flowable<List<Comment>>): Int { var listComments = listOf<Comment>() var listCommentSize = 0 commentsByPostIdCall .subscribeOn(Schedulers.io()) .subscribe(object : Subscriber<List<Comment>> { override fun onError(t: Throwable?) { Log.d(this.toString(), " Read of comments failed with the following message: " + t?.message); } override fun onNext(comment: List<Comment>) { listComments = comment } override fun onComplete() { print("onComplete!") listCommentSize = listComments.size } override fun onSubscribe(s: Subscription?) { if (s != null) { s.request(1) } } }) return listCommentSize } 

其他认为我注意到有时流没有去onComplete,有时它仍然onNext上被阻止。 不明白为什么?

任何帮助将不胜感激! 非常感谢 :)

这是我将如何解决它:

 Flowable.zip<User, Comments, Pair<User, Comments>>( postService.getUser(postId), postService.getCommentsByPostId(postId), BiFunction { user, comments -> Pair(user, comments) }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .bindToLifecycle(this) .map { (first, second) -> Triple(first, second, ExtraDatasFromSomewhere) } .subscribe({ Log.d("MainActivity", "OnNext") }, { Log.d("MainActivity", "OnError") }, { Log.d("MainActivity", "OnComplete") }) 

如果zipWith调用不依赖于对方,请使用zipzipWith函数来实现您的目标。
你可以在这里找到更多:
RxZip(): http://reactivex.io/documentation/operators/zip ://reactivex.io/documentation/operators/zip。

您可以像这样一起轻松地将服务器中的数据与mainActivity数据一起映射:

 .map { (first, second) -> Triple(first, second, ExtraDatasFromSomewhere) } 

Kotlin对于lambda函数有一个非常漂亮的语法,所以我鼓励你使用它们和特定的订阅函数:
subscribe(): http://reactivex.io/RxJava/javadoc/io/reactivex/Flowable.html#subscribe(io.reactivex.functions.Consumer,%20io.reactivex.functions.Consumer,%20io.reactivex.functions.Action) : http://reactivex.io/RxJava/javadoc/io/reactivex/Flowable.html#subscribe(io.reactivex.functions.Consumer,%20io.reactivex.functions.Consumer,%20io.reactivex.functions.Action) ( http://reactivex.io/RxJava/javadoc/io/reactivex/Flowable.html#subscribe(io.reactivex.functions.Consumer,%20io.reactivex.functions.Consumer,%20io.reactivex.functions.Action)

另外非常重要的是要注意 ,我没有使用只有原始的Rxjava2库。 我用下面的库: RxAndroid
observeOn(AndroidSchedulers.mainThread())获取mainThread。 这是因为您操作了UI而没有指定您订阅的线程。 有了这个,你可以实现你的订阅将在mainThread处理。
RxLifecycle
.bindToLifecycle(this)这将确保你不会留下内存泄漏,如果活动已关闭,但您的retrofit2调用没有完成

我刚刚根据我的需要调整了Kioba建议的解决方案。 我在这里发布这个,以防某人有用。 我不知道这是不是一个优雅的方式来获得评论数量。 我刚刚使用List <Comment>而不是Comment ,然后我做了一些像it.second.size.toString()来获得评论的数量。
由于我只需要两个数据:用户和评论我决定使用Pair而不是Triple。

 Flowable.zip<User, List<Comment>, Pair<User, List<Comment>>>( postService.getUser(post.id), postService.getCommentsByPostId(post.id), BiFunction { user, comments -> Pair(user, comments) }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .map { (first, second) -> Pair(first, second) } .subscribe({ Log.d("MainActivity", "OnNext") userTextView.text = it.first.name title.text = post.title body.text = post.body number_comments.text = it.second.size.toString() }, { Log.d("MainActivity", "OnError") }, { Log.d("MainActivity", "OnComplete") })