如何在不等待结果的情况下在另一个函数中运行暂停函数?

问题描述

我有一种情况,我的代码必须发送一个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内(我读到的在悬挂函数内执行不正确)之外,还有另一种方法可以在存储库?

解决方法

您想并行执行多个任务,但是当所有任务完成时返回函数。如果我是对的。

您可以使用async / await。内部暂停功能

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