合并保留订单的 Kotlin 流程
Merge Kotlin flows preserving the orders
我有一个与 Kotlin 流程相关的问题。
假设有两个网络 APIs:
- 一个是获取ID列表;和
- 另一个给一个ID,得到一个用户
我要什么
- 使用第一个 API 获取 ID
- 使用第二个API获取所有用户
- Return要UI显示的用户列表
对我来说,这看起来像是 Kotlin 流的完美用例。我可能会这样做:
// NetworkApi.kt
interface NetworkApi {
@GET("ids")
suspend fun getIds(): List<Int>
@GET("users/{id}")
suspend fun getUser(id: Int): User
}
在我的 ViewModel 中:
class MyViewModel(private val networkApi: NetworkApi): ViewModel() {
val usersLiveData = flow {
emit(networkApi.getIds())
}.flatMapConcat { // it: List<Int>
val flowList = mutableListOf<Flow<User>>()
val userList = mutableListOf<User>()
for (id in it) {
flowList.add(flow{ emit(networkApi.getUser(id)) })
}
flowList.merge().toList(userList)
userList
}.asLiveData()
}
请注意,我使用 merge
并行发送用户请求(而不是一个接一个),以缩短延迟。
但是,根据merge
的documentation,它不会是“保留元素的顺序”。
我想要享受并行化的好处,以及保留元素的顺序。请问有办法吗?
我看不出这与 Flows 有何完美契合。你请求一次,你得到一次结果。它不是不断变化的数据流。 (如果每次网络列表更改时您都自动检索新列表,那么 Flows 就有意义了。)
如果你从这些方面考虑,代码非常简单,你只需要公开一个挂起函数。
class MyViewModel(private val networkApi: NetworkApi): ViewModel() {
suspend fun getUsers(): List<User> = networkApi.getIds()
.map { async { networkApi.getUser(it) } }
.awaitAll()
}
如果您真的想将其公开为 LiveData(只会发布一个值):
val usersLiveData: LiveData<List<User>> = MutableLiveData<List<User>>().apply {
viewModelScope.launch {
value = getUsers()
}
}
或者将其公开为只有一个发布值的 SharedFlow:
val users: SharedFlow<List<User>> = MutableSharedFlow<List<User>>(replay = 1).apply {
viewModelScope.launch {
emit(getUsers())
}
}
我有一个与 Kotlin 流程相关的问题。
假设有两个网络 APIs:
- 一个是获取ID列表;和
- 另一个给一个ID,得到一个用户
我要什么
- 使用第一个 API 获取 ID
- 使用第二个API获取所有用户
- Return要UI显示的用户列表
对我来说,这看起来像是 Kotlin 流的完美用例。我可能会这样做:
// NetworkApi.kt
interface NetworkApi {
@GET("ids")
suspend fun getIds(): List<Int>
@GET("users/{id}")
suspend fun getUser(id: Int): User
}
在我的 ViewModel 中:
class MyViewModel(private val networkApi: NetworkApi): ViewModel() {
val usersLiveData = flow {
emit(networkApi.getIds())
}.flatMapConcat { // it: List<Int>
val flowList = mutableListOf<Flow<User>>()
val userList = mutableListOf<User>()
for (id in it) {
flowList.add(flow{ emit(networkApi.getUser(id)) })
}
flowList.merge().toList(userList)
userList
}.asLiveData()
}
请注意,我使用 merge
并行发送用户请求(而不是一个接一个),以缩短延迟。
但是,根据merge
的documentation,它不会是“保留元素的顺序”。
我想要享受并行化的好处,以及保留元素的顺序。请问有办法吗?
我看不出这与 Flows 有何完美契合。你请求一次,你得到一次结果。它不是不断变化的数据流。 (如果每次网络列表更改时您都自动检索新列表,那么 Flows 就有意义了。)
如果你从这些方面考虑,代码非常简单,你只需要公开一个挂起函数。
class MyViewModel(private val networkApi: NetworkApi): ViewModel() {
suspend fun getUsers(): List<User> = networkApi.getIds()
.map { async { networkApi.getUser(it) } }
.awaitAll()
}
如果您真的想将其公开为 LiveData(只会发布一个值):
val usersLiveData: LiveData<List<User>> = MutableLiveData<List<User>>().apply {
viewModelScope.launch {
value = getUsers()
}
}
或者将其公开为只有一个发布值的 SharedFlow:
val users: SharedFlow<List<User>> = MutableSharedFlow<List<User>>(replay = 1).apply {
viewModelScope.launch {
emit(getUsers())
}
}