kotlin 在Android中,如何指定BLE ScanCallback正在哪个线程上运行?

liwlm1x9  于 2023-11-21  发布在  Kotlin
关注(0)|答案(1)|浏览(151)

Android.Kotlin.

你好,我很感激一些帮助了解线程如何在这里工作:)
我有一个BLE扫描器类。它的方法scan()Dispatcher.IO运行所有东西。我设法确认它的代码不在主线程上运行。在它里面我创建了一个suspendCancellableCoroutine,在它里面我创建了一个ScanCallback。我假设回调的方法会在创建回调的同一个线程上运行。但它不是-它运行在主线程上,可能会阻塞UI。

问题:有没有办法确保ScanCallback'的方法,如onScanResultonScanFailed运行在同一个线程上,其余的FakeScaner.scan()方法运行在同一个线程上?

原因:在某些情况下,我需要停止扫描仪,睡眠几秒钟,然后重新启动它。我设法做了一个变通方案,但我仍然想弄清楚为什么它能正常工作,以及如果可能的话如何改变它:)

  1. class FakeScanner(
  2. private val context: Context,
  3. private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO) {
  4. private val bluetoothAdapter: BluetoothAdapter by lazy {
  5. val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
  6. requireNotNull(bluetoothManager.adapter)
  7. }
  8. suspend fun scan(timeout: Duration?): Map<MyDevice, SignalStrength> =
  9. withContext(ioDispatcher) {
  10. if (Looper.myLooper() == Looper.getMainLooper()) {
  11. Log.d(TAG, "This is running MAIN thread")
  12. } else {
  13. Log.d(TAG, "This is running NOT on MAIN thread")
  14. }
  15. /**
  16. * Some code here
  17. */
  18. suspendCancellableCoroutine { cont ->
  19. val bleDevices = mutableMapOf<BluetoothDevice, SignalStrength>()
  20. val scanCallback = object : ScanCallback() {
  21. @Synchronized
  22. override fun onScanResult(callbackType: Int, result: ScanResult?) {
  23. if (Looper.myLooper() == Looper.getMainLooper()) {
  24. Log.d(TAG, "This is running MAIN thread")
  25. } else {
  26. Log.d(TAG, "This is running NOT on MAIN thread")
  27. }
  28. try {
  29. result?.device?.let {
  30. bleDevices.put(it, SignalStrength(result.rssi))
  31. }
  32. } catch (t: Throwable) {
  33. if (cont.isActive) { cont.resumeWithException(t) }
  34. }
  35. }
  36. @Synchronized
  37. override fun onScanFailed(errorCode: Int) {
  38. try {
  39. // Some logic about scan attempt limits..
  40. when (errorCode) {
  41. SCAN_FAILED_ALREADY_STARTED -> { /* Restart scanner after delay */ }
  42. else -> { /* Logic about other error codes */ }
  43. }
  44. } catch (t: Throwable) {
  45. if (cont.isActive) { cont.resumeWithException(t) }
  46. }
  47. }
  48. }
  49. try {
  50. // Start scanning
  51. } catch (t: Throwable) {
  52. if (cont.isActive) {
  53. cont.resumeWithException(t)
  54. }
  55. }
  56. cont.invokeOnCancellation {
  57. try {
  58. // Stop scanner here
  59. } catch (t: SecurityException) {
  60. // Nothing to do here
  61. }
  62. }
  63. }
  64. }
  65. }

字符串

qybjjes1

qybjjes11#

不,不幸的是没有。它是硬编码在这里,它将运行在主线程:https://android.googlesource.com/platform/packages/modules/Bluetooth/+/aa58f747f37494c619a9afae1622f56001bc07fb/framework/java/android/bluetooth/le/BluetoothLeScanner.java#543。
以前在Android 4.4中,扫描结果直接在Binder线程上交付,该线程内部接收来自蓝牙进程的结果。我真的不知道他们为什么要这样改变。
如果您想在不同的线程上处理结果,则需要手动将结果发布到该线程。

相关问题