在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
调用不依赖于对方,请使用zip
或zipWith
函数来实现您的目标。
你可以在这里找到更多:
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") })