在 Kotlin 中使用 Flowable 的多个 retrofit2 请求
Multiple retrofit2 requests using Flowable in Kotlin
为了提高我在 kotlin、Rx、Retrofit2 方面的技能,我决定做一个演示项目。
演示项目包括在回收站视图中显示 posts,然后在 activity.
中显示 post 的详细信息
我在显示来自不同 api 调用的数据时遇到了困难:用户名、标题、post 的 body 和 post 的评论数。
我的问题是我想执行多个请求,然后获得所有需要的数据以便详细显示它们 activity。这意味着打一个电话给我用户名,然后打一个电话给我 post 的评论数。 post 的标题和 body 来自主要 activity 中完成的请求,我只是将其与捆绑包一起发送到详细信息 activity。
Api 调用:
// return post 1
的注释
http://jsonplaceholder.typicode.com/comments?postId=1
// return用户2的信息
http://jsonplaceholder.typicode.com/users/2
//调用用于在主post中显示activity
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")
})
如果 retrofit2 调用不相互依赖,请使用 zip
或 zipWith
函数来实现您的目标。
您可以在这里找到更多信息:
RxZip() : http://reactivex.io/documentation/operators/zip
。
您可以像这样轻松地将来自服务器的数据与 mainActivity 数据映射在一起:
.map { (first, second) -> Triple(first, second, ExtraDatasFromSomewhere) }
Kotlin 具有非常漂亮的 lambda 函数语法,因此我鼓励您将它们与特定的订阅函数一起使用:
订阅():http://reactivex.io/RxJava/javadoc/io/reactivex/Flowable.html#subscribe(io.reactivex.functions.Consumer,%20io.reactivex.functions.Consumer,%20io.reactivex.functions.Action)
同样非常重要的是要注意我并没有只使用原始的 Rxjava2 库。我使用了以下库:
RxAndroid
for observeOn(AndroidSchedulers.mainThread())
获取主线程。这是因为您在未指定您订阅的线程的情况下操纵了 UI。有了这个,您可以实现您的订阅将在 mainThread 上处理。
RxLifecycle
对于 .bindToLifecycle(this)
这将确保如果 activity 已关闭但您的 retrofit2 调用未完成,您不会留下内存泄漏
我刚刚根据自己的需要调整了 Kioba 建议的解决方案。我 post 在这里,以防它对某人有用。
我不知道这是否是一种获取评论数量的优雅方式。我刚刚使用 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")
})
为了提高我在 kotlin、Rx、Retrofit2 方面的技能,我决定做一个演示项目。
演示项目包括在回收站视图中显示 posts,然后在 activity.
中显示 post 的详细信息
我在显示来自不同 api 调用的数据时遇到了困难:用户名、标题、post 的 body 和 post 的评论数。
我的问题是我想执行多个请求,然后获得所有需要的数据以便详细显示它们 activity。这意味着打一个电话给我用户名,然后打一个电话给我 post 的评论数。 post 的标题和 body 来自主要 activity 中完成的请求,我只是将其与捆绑包一起发送到详细信息 activity。
Api 调用:
// return post 1
的注释
http://jsonplaceholder.typicode.com/comments?postId=1
// return用户2的信息
http://jsonplaceholder.typicode.com/users/2
//调用用于在主post中显示activity
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")
})
如果 retrofit2 调用不相互依赖,请使用 zip
或 zipWith
函数来实现您的目标。
您可以在这里找到更多信息:
RxZip() : http://reactivex.io/documentation/operators/zip
。
您可以像这样轻松地将来自服务器的数据与 mainActivity 数据映射在一起:
.map { (first, second) -> Triple(first, second, ExtraDatasFromSomewhere) }
Kotlin 具有非常漂亮的 lambda 函数语法,因此我鼓励您将它们与特定的订阅函数一起使用:
订阅():http://reactivex.io/RxJava/javadoc/io/reactivex/Flowable.html#subscribe(io.reactivex.functions.Consumer,%20io.reactivex.functions.Consumer,%20io.reactivex.functions.Action)
同样非常重要的是要注意我并没有只使用原始的 Rxjava2 库。我使用了以下库:
RxAndroid
for observeOn(AndroidSchedulers.mainThread())
获取主线程。这是因为您在未指定您订阅的线程的情况下操纵了 UI。有了这个,您可以实现您的订阅将在 mainThread 上处理。
RxLifecycle
对于 .bindToLifecycle(this)
这将确保如果 activity 已关闭但您的 retrofit2 调用未完成,您不会留下内存泄漏
我刚刚根据自己的需要调整了 Kioba 建议的解决方案。我 post 在这里,以防它对某人有用。
我不知道这是否是一种获取评论数量的优雅方式。我刚刚使用 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")
})