试着理解频道。我想要引导安卓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。
EDIT1:,根据docs:The channel is closed when the coroutine completes.,这是有意义的。我知道我们可以将suspendCoroutine和resume一起用于一次callback-replacement。然而,这是一个侦听器/流-情况。我不想让协同线完成
发布于 2019-05-23 21:10:26
使用produce,您可以将范围引入您的频道。这意味着,生成在通道上流的项的代码可以被取消。
这也意味着您的通道的生存期从produce的lambda开始,到此lambda结束时结束。
在您的示例中,produce调用的lambda几乎立即结束,这意味着您的通道几乎立即关闭。
将代码更改为如下内容:
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(...)
}
}
}https://stackoverflow.com/questions/56257990
复制相似问题