如何在另一个函数中运行挂起函数而不等待其结果?



>我有一个场景,我的代码必须发送一个 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中(我已阅读在挂起函数中执行此操作不正确)之外,还有另一种方法可以在存储库中执行此操作?

您可以根据需要在存储库中使用coroutineScopesupervisorScope。这两个函数都是为并行分解工作而设计的。一旦给定块及其所有子协程完成,这些函数就会返回。

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()
}

最新更新