为了提高我在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上被阻止。不明白为什么?
任何帮助都会非常感激!非常感谢:)
答案 0 :(得分:3)
这就是我如何解决它:
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")
})
如果retrofit2调用不相互依赖,请使用zip
或zipWith
函数来实现目标。
你可以在这里找到更多:
RxZip():http://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)
同样非常重要的是要注意我没有使用原始的Rxjava2 lib。我使用下面的库:
RxAndroid
让observeOn(AndroidSchedulers.mainThread())
获取mainThread。这是因为您操纵了UI而未指定您订阅的线程。有了这个,您可以实现您的订阅将在mainThread上处理
RxLifecycle
对于.bindToLifecycle(this)
,如果活动已关闭但您的retrofit2调用未完成,这将确保您不会留下内存泄漏
答案 1 :(得分:1)
我刚刚根据我的需要调整了Kioba建议的解决方案。我在这里发布,以防它对某人有用。
我不知道这是否是获得评论数量的优雅方式。我刚用过 List&lt;评论&gt; 而不是评论然后我执行类似 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")
})