android - 将广播接收器包装到流中(协程)
问题描述
我有一个用于 wifi 扫描结果的广播接收器作为数据源,我想以协程方式制作它。我在这里找到了暂停功能的答案: https ://stackoverflow.com/a/53520496/5938671
suspend fun getCurrentScanResult(): List<ScanResult> =
suspendCancellableCoroutine { cont ->
//define broadcast reciever
val wifiScanReceiver = object : BroadcastReceiver() {
override fun onReceive(c: Context, intent: Intent) {
if (intent.action?.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) == true) {
context.unregisterReceiver(this)
cont.resume(wifiManager.scanResults)
}
}
}
//setup cancellation action on the continuation
cont.invokeOnCancellation {
context.unregisterReceiver(wifiScanReceiver)
}
//register broadcast reciever
context.registerReceiver(wifiScanReceiver, IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
//kick off scanning to eventually receive the broadcast
wifiManager.startScan()
}
这对于信号发射来说很好,但如果我想在扫描过程中获得结果,那么我会崩溃,因为cont.resume()
只能调用一次。然后我决定试试Flow
。这是我的代码:
suspend fun getCurrentScanResult(): Flow<List<ScanResult>> =
flow{
val wifiScanReceiver = object : BroadcastReceiver() {
override fun onReceive(c: Context, intent: Intent) {
if (intent.action?.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) == true) {
//context.unregisterReceiver(this)
emit(wifiManager.scanResults)
}
}
}
//setup cancellation action on the continuation
//register broadcast reciever
context.registerReceiver(wifiScanReceiver, IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
//kick off scanning to eventually receive the broadcast
wifiManager.startScan()
}
但是现在Android Stuidio 说Suspension functions can be called only within coroutine body
对于函数emit(wifiManager.scanResults)
有没有办法在这里使用Flow?
解决方案
请查看专门为此用例设计的回调流程。像这样的东西可以完成这项工作:
callbackFlow {
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
if (intent.action == WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) {
sendBlocking(wifiManager.scanResults) // or non-blocking offer()
}
}
}
context.registerReceiver(receiver, intentFilter)
awaitClose {
context.unregisterReceiver(receiver)
}
}
You also might want to share this flow with e.g. shareIn operator to avoid registering a new receiver for each flow subscriber.
推荐阅读
- laravel - 添加附件时的 Laravel 邮件布局问题
- maven - 如何通过环境变量传递 Maven 编译器参数?
- apache - RewriteCond 不包括域
- javascript - JS如何在一个对象中合并两个json对象,其中on对象的ID对应于第二个对象的相同ID
- spring-boot - 如何在jar文件执行中遍历springboot中资源文件夹下的文件夹
- spring-boot - 如何从 Apache Artemis 获得与从带有通配符 JMS 侦听器的经典 ActiveMQ 获得相同的行为
- neo4j - 获取两个指定节点之间的节点和关系以供审查
- angular - 孩子打开时角度禁用父滚动
- windows - windows 2019 iis无法安装
- swift - SwiftUI:更改类中的值