RxJava 运行 两个 observables 列表作为结果使用来自第二个 observable 中第一个 observable 的结果

RxJava run two observables with lists as results using result from first observable in second observable

我正在尝试进行两次 api 调用并将它们合并,将第二个结果分配给第一个结果。起初我正在考虑使用 zipWith 但对于第二次调用我需要第一个响应中的用户 ID:

@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>
)

所以我想获取用户列表,然后为每个用户获取他的存储库列表并将这些存储库分配给用户。我做了一些研究,发现 solution for similar problem 使用 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]
                        )
                    }
                }
        }
}

它确实有效,但我觉得这不是最好的方法。有谁知道如何使用更好、更清洁的解决方案来实现这一点?

你必须使用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()
}