Несколько запросов retrofit2 с использованием Flowable в Котлине

Чтобы улучшить свои навыки в kotlin, Rx, Retrofit2, я решил сделать демонстрационный проект. Демонстрационный проект состоит в том, чтобы отображать сообщения в ресайклере, а затем отображать детали сообщения в подробном действии.
Я столкнулся с трудностями при отображении данных, поступающих с разных вызовов api: имени пользователя, заголовка, тела сообщения и количества комментариев сообщения.

Моя проблема заключается в том, что я хотел бы выполнить несколько запросов, а затем получить все данные, необходимые для их отображения в подробном действии. Это означает, что вы делаете вызов, который дает мне имя пользователя, а затем звонок, который дает мне количество комментариев для сообщения. Название и тело сообщения исходят из запроса, сделанного в основном действии, который я просто передаю ему с помощью пакета для подробного действия.

Апи звонит:
// вернуть комментарии для сообщения 1
http://jsonplaceholder.typicode.com/comments?postId=1

// возвращает информацию пользователя 2
http://jsonplaceholder.typicode.com/users/2

// вызов используется для отображения сообщений в основном действии
Http: /jsonplaceholder.typicode.com/posts

Я все еще новичок в Rx, я думал использовать FlatMap, но я не знаю, как использовать его с Flowable в kotlin ..

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

Используйте функции zip или zipWith для достижения своей цели, если вызовы retrofit2 не делятся друг на друга.
Вы можете узнать больше здесь:
RxZip (): http://reactivex.io/documentation/operators/zip .

Вы можете легко сопоставить данные с сервера вместе с данными mainActivity следующим образом:

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

У Kotlin очень красивый синтаксис для лямбда-функций, поэтому я бы посоветовал вам использовать их со специальной функцией подписки:
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. Я использовал libs ниже: RxAndroid
для функции observeOn(AndroidSchedulers.mainThread()) для получения mainThread. Это связано с тем, что вы управляете пользовательским интерфейсом без указания потока, на который вы подписаны. С этим вы можете добиться того, что ваша подписка будет обработана на mainThread.
RxLifecycle
для .bindToLifecycle(this) это будет гарантировать, что вы не оставите утечку памяти, если активность закрыта, но ваш вызов retrofit2 не завершился

Я только что адаптировал решение, предложенное Kioba, с моими потребностями. Я размещаю это здесь, если это может быть полезно кому-то. Я не знаю, если это элегантный способ получить количество комментариев. Я просто использовал List <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") }) 
Intereting Posts
Android: соскабливание статей с помощью jsoup Не удалось построить Gradle с помощью Kotlin, Scala и Java Как создать сложный класс, который может предложить некоторые классы для расширения в будущем в Котлине? Android Studio (Kotlin) как преобразовать StringArray в MutableList Как проверить ограничения на инициализацию объекта? Сохранить сторонний объект в ORM Количество экземпляров каждого тега с использованием функционального программирования Файл Scratch не работает на IntelliJ IDEA Инициализация val путем деструктуризации в Котлине Как я могу запускать файлы Kotlin-Script (.kts) из Kotlin / Java? eclipse организует импорт, не работающий с файлами kotlin Подклассификация класса для изменения переменной параметра типа в Котлине Как заменить FrameLayout на активность фрагментом? Простой и приятный способ увеличить значение null в Kotlin Развитие библиотеки. Использование данных из внешнего источника