如何在不等待结果的情况下 运行 在另一个函数中挂起一个函数?
How to run a suspend function inside another one without waiting for its result?
我有一个场景,我的代码必须发送一个 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
中(我读到在挂起函数中这样做是不正确的)还有另一种方法可以做到这一点在存储库中?
您想并行执行多个任务,但 return 在所有任务完成后才能正常工作。如果我是对的。
您可以使用 async/await。内部挂起函数
val d1 = async { t1() }
val d2 = async { t2() }
d1.await()
d2.await()
// all tasks done
t1 和 t2 将 运行 并行。当 t1.await() 调用时它会等待结果但 t2 仍然 运行ning.
在您的函数中,您可以这样更改它:
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()
}
is there another way of doing this inside the repository?
没有
(which I have read is incorrect to do inside a suspending function)
在挂起函数中使用 launch
是完全可以的,即发即忘任务
查看 coroutineScope 函数是否满足您的要求:
Creates a CoroutineScope and calls the specified suspend block with this scope. The provided scope inherits its coroutineContext from the outer scope, but overrides the context's Job.
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)
}
}
您可以根据需要在存储库中使用 coroutineScope
or supervisorScope
。这两个功能都是为工作的并行分解而设计的。一旦给定块及其所有子协程完成,这些函数 return。
当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)
将并行执行。
我有一个场景,我的代码必须发送一个 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
中(我读到在挂起函数中这样做是不正确的)还有另一种方法可以做到这一点在存储库中?
您想并行执行多个任务,但 return 在所有任务完成后才能正常工作。如果我是对的。
您可以使用 async/await。内部挂起函数
val d1 = async { t1() }
val d2 = async { t2() }
d1.await()
d2.await()
// all tasks done
t1 和 t2 将 运行 并行。当 t1.await() 调用时它会等待结果但 t2 仍然 运行ning.
在您的函数中,您可以这样更改它:
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()
}
is there another way of doing this inside the repository?
没有
(which I have read is incorrect to do inside a suspending function)
在挂起函数中使用 launch
是完全可以的,即发即忘任务
查看 coroutineScope 函数是否满足您的要求:
Creates a CoroutineScope and calls the specified suspend block with this scope. The provided scope inherits its coroutineContext from the outer scope, but overrides the context's Job.
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)
}
}
您可以根据需要在存储库中使用 coroutineScope
or supervisorScope
。这两个功能都是为工作的并行分解而设计的。一旦给定块及其所有子协程完成,这些函数 return。
当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)
将并行执行。