Rx Java запустить две наблюдаемые со списками в качестве результатов, используя результат из первой наблюдаемой во второй наблюдаемой - PullRequest
0 голосов
/ 11 апреля 2020

Я пытаюсь сделать два вызова API и объединить их, назначить второй результат для первого. Сначала я думал об использовании zipWith, но для второго вызова мне нужен идентификатор пользователя из ответа первого:

@GET("users")
fun getUsers(): Single<List<User>>

@GET("users/{userId}/repos")
fun getUserRepositories(@Path("userId") userLogin: String): Single<List<Repository>>

И объект пользователя выглядит так:

data class User(
    val id: Int,
    val login: String,
    val repositories: List<Repository>
)

Поэтому я хотел бы получить список пользователей, а затем для каждого пользователя получить список своих репозиториев и назначить эти репозитории пользователю. Я провел некоторое исследование и нашел решение для аналогичной проблемы с использованием flatMap. Теперь я хотел бы сделать что-то вроде этого, но в моем случае у меня есть список объектов в ответ на первый запрос, и я не знаю, как с этим справиться. Сейчас я придумал что-то вроде этого:

private fun getUsers(): Single<List<User>> {
    return api.getUsers()
        .flatMap { users ->
            Single.zip(users.map { user ->
                api.getUserRepositories(user.login)
            }, { it.map {it as List<Repository> } })
                .map { repositories ->
                    users.mapIndexed { index, user ->
                        User(
                            id = user.id,
                            login = user.login,
                            repositories = repositories[index]
                        )
                    }
                }
        }
}

Это работает, но я чувствую, что это не лучший способ сделать это. Кто-нибудь знает, как этого добиться с помощью лучшего, более чистого решения?

1 Ответ

2 голосов
/ 12 апреля 2020

Вы должны использовать метод publish:

data class Repository(
    val name: String
)

data class User(
    val id: Int,
    val login: String,
    val repositories: List<Repository>
)

interface Api {
    fun getUsers(): Single<List<User>>
    fun getUserRepositories(id: Int): Single<List<Repository>>
}

fun getApi(): Api {
    TODO()
}

fun getUsers(): Single<List<User>> {
    val api: Api = getApi()

    return api
        .getUsers()
        .toObservable()
        .flatMapIterable { it }
        .publish { user ->
            Observable.zip(
                user,
                user.flatMap { user -> api.getUserRepositories(user.login).toObservable() },
                BiFunction { user, repositories ->
                    user.copy(repositories = repositories)
                }
            )
        }
        .toList()
}
...