如何在Ble回调执行后从ViewModel的Kotlin函数返回结果?
问题分析
你的代码里,connectToCharger是同步函数,但蓝牙设备连接是异步操作——scanForDevicesAndConnectTohomeCharger会立刻执行完毕,函数直接返回初始的NoDataFailure,而onBleDeviceStateChange回调要等到蓝牙状态变化时才会触发,这时候函数早就返回了,回调里修改的result变量对返回值没有任何影响。
要实现"等待回调触发后再返回结果",有两种常用的解决方案,适配ViewModel的使用场景:
方案一:用Kotlin协程+CompletableDeferred(推荐)
把函数改成挂起函数,通过CompletableDeferred等待异步回调的结果,适合需要直接获取返回值的场景:
// 改成suspend挂起函数 private suspend fun connectToCharger(activity: Activity): NoDataResult { val deferred = CompletableDeferred<NoDataResult>() blufiHelper.scanForDevicesAndConnectTohomeCharger( activity, "homewifi1", object : BleStateCallback { override fun updateMessage(message: String) { Timber.d("xxx VM $message") // 这里可以保留LiveData更新UI逻辑 // _connectMessage.value = message } override fun onBleDeviceStateChange(state: BleDeviceState) { Timber.d("xxx VM onBleDeviceStateChange $state") val result = when (state) { BleDeviceState.Connected -> NoDataSuccess BleDeviceState.Disconnected -> NoDataFailure(RuntimeException("连接失败:设备断开")) else -> NoDataFailure(RuntimeException("连接失败:未知状态")) } // 把结果传递给deferred deferred.complete(result) } }) // 可选:添加超时处理,避免无限等待 return withContext(Dispatchers.IO) { withTimeoutOrNull(30_000) { // 30秒超时 deferred.await() } ?: NoDataFailure(RuntimeException("连接超时")) } }
调用方式
在ViewModel的协程作用域里调用(比如viewModelScope):
fun startChargerConnection(activity: Activity) { viewModelScope.launch { val result = connectToCharger(activity) // 处理结果,比如用LiveData通知UI _connectResult.value = result } }
方案二:用LiveData直接传递结果
如果不需要函数返回值,而是让UI层观察结果变化,可以直接用LiveData:
// 在ViewModel里定义LiveData private val _connectResult = MutableLiveData<NoDataResult>() val connectResult: LiveData<NoDataResult> = _connectResult private fun connectToCharger(activity: Activity) { blufiHelper.scanForDevicesAndConnectTohomeCharger( activity, "homewifi1", object : BleStateCallback { override fun updateMessage(message: String) { Timber.d("xxx VM $message") // 可选:用LiveData更新连接过程消息 // _connectMessage.value = message } override fun onBleDeviceStateChange(state: BleDeviceState) { Timber.d("xxx VM onBleDeviceStateChange $state") val result = when (state) { BleDeviceState.Connected -> NoDataSuccess BleDeviceState.Disconnected -> NoDataFailure(RuntimeException("连接失败:设备断开")) else -> NoDataFailure(RuntimeException("连接失败:未知状态")) } // 发布结果到LiveData,用postValue确保主线程更新 _connectResult.postValue(result) } }) }
UI层观察结果
viewModel.connectResult.observe(this) { result -> when(result) { is NoDataSuccess -> // 处理连接成功逻辑 is NoDataFailure -> // 处理连接失败逻辑,比如显示错误提示 } }
内容的提问来源于stack exchange,提问作者BRDroid
相关产品推荐
相关产品推荐

