提问人:Karolis 提问时间:11/17/2023 更新时间:11/18/2023 访问量:26
在 Android 中,如何指定 BLE ScanCallback 在哪个线程上运行?
In Android, how to specify on which thread the BLE ScanCallback is running?
问:
人造人。科特林。
您好,我希望能帮助理解线程在这里的工作原理:)
我有一个 BLE 扫描仪类。它的方法使用 运行所有内容。我设法确认它的代码不在主线程上运行。在它里面我创造了一个,在里面我创造了一个.我假设回调的方法将在创建回调的同一线程上运行。但事实并非如此 - 它在主线程上运行,可能会阻塞 UI。scan()
Dispatcher.IO
suspendCancellableCoroutine
ScanCallback
问题:有没有办法确保 s 方法与其余方法运行在同一线程上?ScanCallback'
onScanResult
onScanFailed
FakeScaner.scan()
原因:在某些情况下,我需要停止扫描仪,休眠几秒钟,然后重新启动它。我设法做了一个解决方法,但我仍然想弄清楚为什么它有效,以及如何在可能的情况下更改它:)
class FakeScanner(
private val context: Context,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO) {
private val bluetoothAdapter: BluetoothAdapter by lazy {
val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
requireNotNull(bluetoothManager.adapter)
}
suspend fun scan(timeout: Duration?): Map<MyDevice, SignalStrength> =
withContext(ioDispatcher) {
if (Looper.myLooper() == Looper.getMainLooper()) {
Log.d(TAG, "This is running MAIN thread")
} else {
Log.d(TAG, "This is running NOT on MAIN thread")
}
/**
* Some code here
*/
suspendCancellableCoroutine { cont ->
val bleDevices = mutableMapOf<BluetoothDevice, SignalStrength>()
val scanCallback = object : ScanCallback() {
@Synchronized
override fun onScanResult(callbackType: Int, result: ScanResult?) {
if (Looper.myLooper() == Looper.getMainLooper()) {
Log.d(TAG, "This is running MAIN thread")
} else {
Log.d(TAG, "This is running NOT on MAIN thread")
}
try {
result?.device?.let {
bleDevices.put(it, SignalStrength(result.rssi))
}
} catch (t: Throwable) {
if (cont.isActive) { cont.resumeWithException(t) }
}
}
@Synchronized
override fun onScanFailed(errorCode: Int) {
try {
// Some logic about scan attempt limits..
when (errorCode) {
SCAN_FAILED_ALREADY_STARTED -> { /* Restart scanner after delay */ }
else -> { /* Logic about other error codes */ }
}
} catch (t: Throwable) {
if (cont.isActive) { cont.resumeWithException(t) }
}
}
}
try {
// Start scanning
} catch (t: Throwable) {
if (cont.isActive) {
cont.resumeWithException(t)
}
}
cont.invokeOnCancellation {
try {
// Stop scanner here
} catch (t: SecurityException) {
// Nothing to do here
}
}
}
}
}
答:
2赞
Emil
11/18/2023
#1
不,不幸的是没有。 这里是硬编码的,它将在主线程上运行:https://android.googlesource.com/platform/packages/modules/Bluetooth/+/aa58f747f37494c619a9afae1622f56001bc07fb/framework/java/android/bluetooth/le/BluetoothLeScanner.java#543。
之前,在 Android 4.4 中,扫描结果直接在 Binder 线程上传送,该线程在内部接收来自蓝牙进程的结果。我真的不知道他们为什么这样改变它。
如果要在其他线程上处理结果,则需要自行手动将结果发布到该线程。
评论
0赞
Karolis
11/18/2023
谢谢!这很不幸,但至少现在我知道了:)
评论