基于RXAndroidBLE监听蓝牙连接状态及UI适配问题
解决BLE连接状态监听与UI更新问题
首先得说,你代码里的核心问题是过早调用了disposable.dispose()——这行代码会立刻终止establishConnection的订阅,导致连接还没建立就被取消,所以内部的println和状态监听代码根本没机会执行。另外还有嵌套订阅、不必要的null判断这些小问题,我帮你一步步梳理并给出正确实现:
先搞懂所有BLE连接状态
RxBleConnection.RxBleConnectionState是个枚举类,包含4种状态,你需要全部覆盖来适配UI:
DISCONNECTED:设备未连接CONNECTING:正在连接中CONNECTED:已成功连接DISCONNECTING:正在断开连接
正确的实现方式
方案1:分开监听状态与建立连接(直观易维护)
这种方式把状态监听和连接操作分开,逻辑更清晰:
val rxBleClient = RxBleClient.create(this.context!!) val bleDevice = rxBleClient.getBleDevice("34:81:F4:3C:2D:7B") // 1. 先订阅连接状态变化,确保能捕获所有状态 val stateDisposable = bleDevice.observeConnectionStateChanges() // 必须切换到主线程更新UI,否则会报错 .observeOn(AndroidSchedulers.mainThread()) .subscribe({ connectionState -> println("Connection State: $connectionState") // 用when匹配所有状态,更新对应UI when(connectionState) { RxBleConnection.RxBleConnectionState.CONNECTED -> { enableBluetooth.setBackgroundResource(R.drawable.bluetooth_on) deviceConnected.setText(R.string.connected_to_hooplight) } RxBleConnection.RxBleConnectionState.CONNECTING -> { deviceConnected.setText(R.string.connecting_to_hooplight) // 可以加个加载动画之类的 } RxBleConnection.RxBleConnectionState.DISCONNECTING -> { deviceConnected.setText(R.string.disconnecting_from_hooplight) } RxBleConnection.RxBleConnectionState.DISCONNECTED -> { enableBluetooth.setBackgroundResource(R.drawable.bluetooth_off) deviceConnected.setText(R.string.connect_to_hooplight) } } }, { throwable -> Log.d("State Error", "监听状态失败: ${throwable.message}") }) // 2. 建立BLE连接(autoConnect=true) val connectionDisposable = bleDevice.establishConnection(true) .subscribe({ rxBleConnection -> // 连接成功后,这里可以执行GATT操作(比如读写特征) Log.d("BLE", "连接成功,可进行GATT通信") }, { throwable -> Log.d("Connection Error", "连接失败: ${throwable.message}") }) // 3. 关键!在合适的时机销毁订阅(比如页面销毁时) override fun onDestroy() { super.onDestroy() stateDisposable.dispose() connectionDisposable.dispose() }
方案2:用RxJava操作符组合流(响应式风格)
如果更习惯RxJava的链式调用,可以用flatMap把连接和状态监听合并:
val rxBleClient = RxBleClient.create(this.context!!) val bleDevice = rxBleClient.getBleDevice("34:81:F4:3C:2D:7B") val combinedDisposable = bleDevice.establishConnection(true) .flatMap { connection -> // 连接成功后,同时监听状态变化,先发射一次已连接状态 bleDevice.observeConnectionStateChanges() .startWithItem(RxBleConnection.RxBleConnectionState.CONNECTED) } .observeOn(AndroidSchedulers.mainThread()) .subscribe({ connectionState -> println("Connection State: $connectionState") // 同样用when处理UI更新,代码同方案1 when(connectionState) { RxBleConnection.RxBleConnectionState.CONNECTED -> { enableBluetooth.setBackgroundResource(R.drawable.bluetooth_on) deviceConnected.setText(R.string.connected_to_hooplight) } RxBleConnection.RxBleConnectionState.CONNECTING -> { deviceConnected.setText(R.string.connecting_to_hooplight) } RxBleConnection.RxBleConnectionState.DISCONNECTING -> { deviceConnected.setText(R.string.disconnecting_from_hooplight) } RxBleConnection.RxBleConnectionState.DISCONNECTED -> { enableBluetooth.setBackgroundResource(R.drawable.bluetooth_off) deviceConnected.setText(R.string.connect_to_hooplight) } } }, { throwable -> Log.d("BLE Error", "操作失败: ${throwable.message}") }) // 页面销毁时清理资源 override fun onDestroy() { super.onDestroy() combinedDisposable.dispose() }
几个重要注意事项
- 绝对不能提前调用
dispose():这是你最初代码不执行println的核心原因——dispose()会立刻取消订阅,连接流程直接终止。必须在不需要连接时(比如页面关闭、用户主动断开)再调用。 - UI更新必须在主线程:RxJava默认可能在子线程发射事件,所以一定要加
observeOn(AndroidSchedulers.mainThread()),否则会抛出UI线程异常。 - 覆盖所有枚举状态:不要漏掉
CONNECTING和DISCONNECTING,否则用户会看不到连接过程中的状态反馈,体验不好。 - 错误处理不能少:每个
subscribe都要处理错误回调,避免未捕获异常导致崩溃。
内容的提问来源于stack exchange,提问作者Martin Erlic
相关产品推荐
相关产品推荐

