Android.Kotlin.
你好,我很感激一些帮助了解线程如何在这里工作:)
我有一个BLE扫描器类。它的方法scan()
用Dispatcher.IO
运行所有东西。我设法确认它的代码不在主线程上运行。在它里面我创建了一个suspendCancellableCoroutine
,在它里面我创建了一个ScanCallback
。我假设回调的方法会在创建回调的同一个线程上运行。但它不是-它运行在主线程上,可能会阻塞UI。
问题:有没有办法确保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
}
}
}
}
}
字符串
1条答案
按热度按时间qybjjes11#
不,不幸的是没有。它是硬编码在这里,它将运行在主线程:https://android.googlesource.com/platform/packages/modules/Bluetooth/+/aa58f747f37494c619a9afae1622f56001bc07fb/framework/java/android/bluetooth/le/BluetoothLeScanner.java#543。
以前在Android 4.4中,扫描结果直接在Binder线程上交付,该线程内部接收来自蓝牙进程的结果。我真的不知道他们为什么要这样改变。
如果您想在不同的线程上处理结果,则需要手动将结果发布到该线程。