簡體   English   中英

生產 <Type> 與頻道 <Type> ()

[英]produce<Type> vs Channel<Type>()

試圖了解渠道。 我想頻道化android BluetoothLeScanner。 為什么這樣做:

fun startScan(filters: List<ScanFilter>, settings: ScanSettings = defaultSettings): ReceiveChannel<ScanResult?> {
    val channel = Channel<ScanResult>()
    scanCallback = object : ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult) {
            channel.offer(result)
        }
    }
    scanner.startScan(filters, settings, scanCallback)

    return channel
}

但這不是:

fun startScan(scope: CoroutineScope, filters: List<ScanFilter>, settings: ScanSettings = defaultSettings): ReceiveChannel<ScanResult?> = scope.produce {
    scanCallback = object : ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult) {
            offer(result)
        }
    }
    scanner.startScan(filters, settings, scanCallback)
}

它告訴我Channel was closed第一次要offerChannel was closed

編輯1:根據文檔: The channel is closed when the coroutine completes. 這是有道理的。 我知道我們可以將suspendCoroutineresume用於一鍵式callback -replacement。 但是,這是一個偵聽器/流情況。 我不希望協程完成

使用produce ,您可以將范圍引入您的Channel。 這意味着,可以取消生成通過通道流式傳輸的項目的代碼。

這也意味着您的頻道的生命周期從produce的lambda的起點開始,並在該lambda結束時結束。

在您的示例中, produce調用的lambda幾乎立即結束,這意味着您的Channel幾乎立即關閉。

將您的代碼更改為如下所示:

fun CoroutineScope.startScan(filters: List<ScanFilter>, settings: ScanSettings = defaultSettings): ReceiveChannel<ScanResult?> = produce {
    scanCallback = object : ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult) {
            offer(result)
        }
    }
    scanner.startScan(filters, settings, scanCallback)

    // now suspend this lambda forever (until its scope is canceled)
    suspendCancellableCoroutine<Nothing> { cont ->
        cont.invokeOnCancellation {
            scanner.stopScan(...)
        }
    }
}

...
val channel = scope.startScan(filter)
...
...
scope.cancel() // cancels the channel and stops the scanner.

我添加了suspendCancellableCoroutine<Nothing> { ... } ,使其“永遠”掛起。

更新:以結構化方式使用produce和處理錯誤(允許結構化並發):

fun CoroutineScope.startScan(filters: List<ScanFilter>, settings: ScanSettings = defaultSettings): ReceiveChannel<ScanResult?> = produce {
    // Suspend this lambda forever (until its scope is canceled)
    suspendCancellableCoroutine<Nothing> { cont ->
        val scanCallback = object : ScanCallback() {
            override fun onScanResult(callbackType: Int, result: ScanResult) {
                offer(result)
            }
            override fun onScanFailed(errorCode: Int) {
                cont.resumeWithException(MyScanException(errorCode))
            }
        }
        scanner.startScan(filters, settings, scanCallback)

        cont.invokeOnCancellation {
            scanner.stopScan(...)
        }
    }
}

暫無
暫無

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

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