Android 在一定时间后关闭流
我正在尝试创建一个流,该流将发布发现蓝牙设备的结果 当扫描这样的设备时,一个人永远不会收到一个完成的扫描信号,所以我必须在一段时间后手动停止流动 我目前用于实现上述目标的代码如下: (Android 在一定时间后关闭流,android,kotlin-coroutines,kotlin-coroutines-flow,Android,Kotlin Coroutines,Kotlin Coroutines Flow,我正在尝试创建一个流,该流将发布发现蓝牙设备的结果 当扫描这样的设备时,一个人永远不会收到一个完成的扫描信号,所以我必须在一段时间后手动停止流动 我目前用于实现上述目标的代码如下: (mockScan用于在仿真器上工作时模拟扫描,当我移动到实际设备时,它将替换为正常扫描) 在我的viewmodel上: private fun startScanning() { scanJob?.cancel() //cancel the scanning job if there is any
mockScan
用于在仿真器上工作时模拟扫描,当我移动到实际设备时,它将替换为正常扫描)
在我的viewmodel上:
private fun startScanning() {
scanJob?.cancel() //cancel the scanning job if there is any
_devices.clear() //clear the currently discovered devices
scanJob = launch { //launch a new job
repo.startScanning(10000) //this will call the repo, it creates a flow with the results
.flowOn(dispatcher.IO)
.buffer()
.onCompletion {
scanJob = null
updateState() //this will update the screen state
}
.catch {
Timber.d("Error ${it.message}") //for now I just show the error , later I will handle it
}
.collect { //when a new entry comes
_devices.add(it) //I add it to my existing devices
devices.postValue(_devices) //and post the value to my live data which will be picked up by the adapter
}
}
updateState() //this will update the screen state
}
在我的存储库上
@ExperimentalCoroutinesApi
override fun startScanning(period: Long): Flow<Device> =
callbackFlow {
//this is a dummy interface I created to test scanning
val callback = object : LeScanCallback {
override fun onScanResult(callbackType: Int, result: ScanResult?) {
offer(Device(result!!.device.first!!, result.device.second!!))
}
}
mockScan(callback) //this simulates scanning
val scope = this
launch {
delay(period) //after some time cancel the scope (which should call awaitClose)
scope.cancel()
}
awaitClose {
//here I will put the code that will actually stop the scan from the adapter
Timber.d("Finished")
}
}
上面的场景似乎有效,实际上在10秒后调用了onCompletion
函数,以便我可以清理任何需要的东西
我的问题是,有没有更好的方法来限制流可以运行的时间?还是我一直在使用launch->delay->scope.close()方法
private fun mockScan(callback: LeScanCallback) {
launch {
launch(DispatcherImpl.IO) {
var id = 0
scanning = true
while (scanning) {
id++
delay(Random.nextInt(1, 3) * 1000L)
val device = Pair("address $id", "name $id")
callback.onScanResult(3, ScanResult(device))
}
}
}
}