>我有一个场景,我的代码必须发送一个 api 调用并继续其工作(其中包含另一个 api 调用),而无需等待第一次调用的结果。
现在我在我的视图模型中这样做
fun showItem(id:Int) {
launch{
repo.markItemRead(id)
}
launch {
try {
val item = repo.getItemById(id).getOrThrow
commands.postValue(ShowItemCommand(item))
} catch (t:Throwable) {
commands.postValue(ShowError(R.string.error_retrieve_item))
repo.logError(t)
}
}
}
这将调用具有这两个函数的存储库
suspend fun markItemRead(id) {
try {
service.markItemAsRead(id)
} catch(ignored:Throwable) {
}
}
suspend fun getItemById(id) : Result<ItemData> {
return try {
val response : ItemEntity = service.getItemById(id)
val item = response.toData()
Result.Success(item)
} catch (t:Throwable) {
Result.Failure(t)
}
}
如果存储库完成了所有这些工作,我更喜欢它,因为每次都必须跟随另一个。
不幸的是,当我尝试在我的存储库中做这样的事情时:
suspend fun getItemById(id:Int) : Result<ItemData> {
try {
service.markItemAsRead(id)
} catch(ignored:Throwable) {
}
return try {
val response : ItemEntity = service.getItemById(id)
val item = response.toData()
Result.Success(item)
} catch (t:Throwable) {
Result.Failure(t)
}
}
它等待markItemAsRead
函数完成,然后再继续
除了为存储库定义范围并将markItemAsRead
调用放在launch
中(我已阅读在挂起函数中执行此操作不正确)之外,还有另一种方法可以在存储库中执行此操作?
您可以根据需要在存储库中使用coroutineScope
或supervisorScope
。这两个函数都是为并行分解工作而设计的。一旦给定块及其所有子协程完成,这些函数就会返回。
当coroutineScope
中的任何子协程失败时,此作用域将失败,所有其他子项都将被取消。与coroutineScope
不同,supervisorScope
中子协程的失败不会导致此作用域失败,也不会影响其其他子作用域,因此可以实现用于处理其子项故障的自定义策略。
请选择最适合您需求的产品。用法示例:
suspend fun getItemByIdAndMarkRead(id: Int) : Result<ItemData> = supervisorScope {
launch {
try {
service.markItemAsRead(id)
} catch(ignored:Throwable) { }
}
return@supervisorScope withContext(Dispatchers.Default) {
try {
val response : ItemEntity = service.getItemById(id)
val item = response.toData()
Result.Success(item)
} catch (t: Throwable) {
Result.Failure(t)
}
}
}
service.markItemAsRead(id)
和service.getItemById(id)
将并行执行。
存储库中还有其他方法可以做到这一点吗?
不,没有
(我已经读到在挂起功能中执行此操作不正确)
在暂停功能中使用launch
来执行火灾和忘记任务是完全可以
查看 coroutineScope 函数是否执行您想要的操作:
创建一个协程作用域,并使用此作用域调用指定的挂起块。提供的作用域从外部作用域继承其协程上下文,但覆盖上下文的作业。
suspend fun getItemById(id:Int) : Result<ItemData> {
coroutineScope {
launch {
try {
service.markItemAsRead(id)
} catch(ignored:Throwable) { }
}
}
return try {
val response : ItemEntity = service.getItemById(id)
val item = response.toData()
Result.Success(item)
} catch (t:Throwable) {
Result.Failure(t)
}
}
你想并行执行多个任务,但在所有任务完成后返回函数。 如果我是对的。
您可以使用异步/等待。 内部挂起功能
val d1 = async { t1() }
val d2 = async { t2() }
d1.await()
d2.await()
// all tasks done
t1 和 t2 将并行运行。 当 t1.await() 调用时,它将等待结果,但 t2 仍在运行。
在您的函数中,您可以像这样更改它:
suspend fun getItemById(id:Int) : Result<ItemData> = coroutineScope {
val t1 = async {
try {
service.markItemAsRead(id)
} catch(ignored:Throwable) {
null
}
}
val t2 = async {
try {
val response : ItemEntity = service.getItemById(id)
val item = response.toData()
Result.Success(item)
} catch (t:Throwable) {
Result.Failure(t)
}
}
t1.await()
return@coroutineScope t2.await()
}