簡體   English   中英

如何在不等待結果的情況下在另一個內部運行掛起功能?

[英]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中(我已經讀過在掛起函數中執行此操作是不正確的)之外,還有另一種方法可以在存儲庫中執行此操作嗎?

我有一個場景,我的代碼必須發送一個 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函數完成

除了定義存儲庫的范圍並將markItemAsRead調用放在launch (我讀過在掛起函數中這樣做是不正確的)之外,還有另一種在存儲庫中執行此操作的方法嗎?

在存儲庫中還有另一種方法嗎?

不,沒有

(我讀過在掛起函數中這樣做是不正確的)

在掛起函數中使用launch來完成即launch即棄的任務是完全可以的

查看coroutineScope函數是否滿足您的要求:

創建一個 CoroutineScope 並使用此范圍調用指定的掛起塊。 提供的范圍從外部范圍繼承其 coroutineContext,但覆蓋上下文的 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)
    }
}

您可以根據需要在存儲庫中使用coroutineScopesupervisorScope 這兩個函數都是為並行分解工作而設計的。 一旦給定塊及其所有子協程完成,這些函數就會返回。

當 coroutineScope 中的任何子協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)將並行執行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM