[英]Why does this Kotlin code with generics produce a Type Mismatch compiler error?
[英]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
第一次要offer
時Channel was closed
。
編輯1:根據文檔: The channel is closed when the coroutine completes.
這是有道理的。 我知道我們可以將suspendCoroutine
和resume
用於一鍵式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.