admin管理员组文章数量:1309972
I do have an app where I have to call an endpoint to pull a list of product and another endpoint to pull the list of product type.
The second endpoint only return the list of type but I need to add the type All
and add the total number of products`
So it looks like: -> Endpoint call for list of products: return a json with all the products -> Endpoint call for list of types: return all types.
When all types are received I add the type all at the beginning of the list and count the number of products. So I need to have the first endpoint call done prior to calling the other one.
I did this way for the init:
private var listOfProducts: List<Product> = emptyList()
private var listOfTypes: List<Type> = emptyList()
private var selectedType: String = ""
init {
fetchProducts()
fetchTypes()
}
and the fetch place is call:
fun fetchProducts() {
viewModelScope.launch {
API_CALL {
listOfProducts = response
}
}
}
fun fetchTypes() {
viewModelScope.launch {
API_CALL {
nb_films = listOfProducts.count()
listOfTypes = Type("all", nb_films) + response
}
}
}
So the code is not perfect, but it's just to sum up the issue.
I need to use information from the fetchProducts into the fetchTypes. In some cases, it fails because of the latency to get the data.
Any idea how to block the trigger of the fetchTypes or either making the 2 calls but waiting one to be ended before processing the data
I do have an app where I have to call an endpoint to pull a list of product and another endpoint to pull the list of product type.
The second endpoint only return the list of type but I need to add the type All
and add the total number of products`
So it looks like: -> Endpoint call for list of products: return a json with all the products -> Endpoint call for list of types: return all types.
When all types are received I add the type all at the beginning of the list and count the number of products. So I need to have the first endpoint call done prior to calling the other one.
I did this way for the init:
private var listOfProducts: List<Product> = emptyList()
private var listOfTypes: List<Type> = emptyList()
private var selectedType: String = ""
init {
fetchProducts()
fetchTypes()
}
and the fetch place is call:
fun fetchProducts() {
viewModelScope.launch {
API_CALL {
listOfProducts = response
}
}
}
fun fetchTypes() {
viewModelScope.launch {
API_CALL {
nb_films = listOfProducts.count()
listOfTypes = Type("all", nb_films) + response
}
}
}
So the code is not perfect, but it's just to sum up the issue.
I need to use information from the fetchProducts into the fetchTypes. In some cases, it fails because of the latency to get the data.
Any idea how to block the trigger of the fetchTypes or either making the 2 calls but waiting one to be ended before processing the data
Share Improve this question asked Feb 2 at 20:03 SebSeb 3,2255 gold badges39 silver badges86 bronze badges 3 |2 Answers
Reset to default 0Your API calls run concurrently, causing fetchTypes() to sometimes use an empty listOfProducts.
One solution would be to use StateFlow to reactively chain the calls and guarantee order:
// ViewModel
private val _products = MutableStateFlow<List<Product>>(emptyList())
val products: StateFlow<List<Product>> = _products
private val _types = MutableStateFlow<List<Type>>(emptyList())
val types: StateFlow<List<Type>> = _types
init {
viewModelScope.launch {
// 1. Fetch products first
_products.value = api.getProducts()
// 2. Fetch types AFTER products are loaded
val typesResponse = api.getTypes()
val allType = Type("All", _products.value.size) // Use product count
_types.value = listOf(allType) + typesResponse
}
}
This way getTypes()
starts only after getProducts() succeeds.
I feel like you can use the concept of async await . Here is what I tried to do
init {
viewModelScope.launch {
callA()
callB()
}
}
private suspend fun callA() {
println("***CallA")
coroutineScope {
val deffered = async {
api1 {
listOfProducts = it
}
listOfProducts
}
deffered.await()
println("***callA result ${listOfProducts.size}")
}
}
private suspend fun callB() {
println("***CallB")
coroutineScope {
val deffered = async {
api2 {
println("***size of product = ${listOfProducts.size}")
listOfTypes = it
}
listOfTypes
}
deffered.await()
println("***callB result ${listOfTypes.size}")
}
}
suspend fun api1(callback: (List<Product>) -> Unit) {
println("***api1")
delay(200L)
val mockedResponse = listOf(
Product("a"),
Product("b"),
Product("c"),
Product("d"),
)
callback(mockedResponse)
}
suspend fun api2(callback: (List<Type>) -> Unit) {
println("***api2")
delay(300L)
val mockedResponse = listOf(
Type("a", 1),
Type("b", 1),
Type("c", 1),
Type("d", 1),
)
callback(mockedResponse)
}
This is the order of response,
- ***CallA
- ***api1
- ***callA result 4
- ***CallB
- ***api2
- ***size of product = 4
- ***callB result 4
本文标签: androidTrigger a coroutine when the other is finishedStack Overflow
版权声明:本文标题:android - Trigger a coroutine when the other is finished - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741835623a2400197.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
fetchTypes(fetchProducts())
. With your current code, there is no trivial and reliable solution to the problem. – broot Commented Feb 2 at 21:41fetchTypes
inside thefetchProducts
, after thelistOfProducts =
line. Or to keep the code less tightly coupled, receive a callback by thefetchTypes
and do the above. But this is not really a "coroutine way". These functions should suspend and don't launch anything. – broot Commented Feb 2 at 21:50viewModelScope.launch { fetchProducts() .flatMapLatest { fetchTypes(it) } .collect { println(it) } }
if you are using flows you could do something like this – Raghunandan Commented Feb 3 at 3:39