使用Flutter Blue读取蓝牙设备响应遇null值,如何解决?
解决Flutter Blue读取蓝牙设备响应的问题
你这两种写法都没踩到点子上,我来给你捋捋问题出在哪,以及正确的做法:
首先说你当前代码的问题:
- 方式一:
_rx.read()是单次主动读取特征的当前值,但如果设备是主动通过notify/indicate推送响应(而不是等着被读取),这个方法要么拿不到数据(时机不对),要么只能拿到其中一个分包,而且很容易因为设备还没返回就执行read导致null。 - 方式二:
_tx.write()的返回值根本不是设备的响应!Flutter Blue里这个方法返回的是Future<void>,你把它赋值给List<int>本身就是错误用法,肯定拿不到有效数据。
正确的实现思路
蓝牙设备主动发多个20字节数据包过来,这种场景必须用监听特征值变化流的方式,而不是单次read。步骤如下:
先启用特征的通知/指示功能
首先要确认你的_rx特征(设备用来发响应的那个)支持notify或indicate属性(设备端必须配置这个),然后在连接设备后启用它:// 连接设备成功后,先开启_rx特征的notify(如果设备用indicate就用setIndicateValue) await _rx.setNotifyValue(true);监听特征的数据流,接收所有分包
启用notify后,设备每次发数据过来都会触发流的回调,我们可以在回调里收集数据包,再拼接成完整响应:// 定义一个变量存储完整响应 List<int> completeResponse = []; // 监听_rx特征的数值变化 final subscription = _rx.value.listen((List<int> packet) { print("收到单个数据包: $packet"); // 把当前分包加入完整响应 completeResponse.addAll(packet); // 这里根据你的业务逻辑判断是否收完了: // 比如知道完整响应总长度是60字节(3个20字节包),或者有特定的结束标记 if (completeResponse.length >= 60) { print("完整响应已接收: $completeResponse"); // 处理完后清空,准备下一次响应 completeResponse.clear(); } });写入数据触发响应
之后调用写入方法就可以了,不需要在write后直接read,响应会通过上面的listen回调过来:Future<void> getBackgroundFunction() async { // withoutResponse设为false表示需要蓝牙层的写入确认 await _tx.write(setSetting, withoutResponse: false); // 不用在这里处理响应,交给上面的监听即可 }
额外注意事项
- 一定要确认
_rx的UUID是设备用来发送响应的正确特征UUID,别搞混了。 - 如果设备用的是indicate(带确认的推送),记得把
setNotifyValue(true)换成setIndicateValue(true)。 - 如果不再需要监听,记得调用
subscription.cancel()取消订阅,避免内存泄漏。
内容的提问来源于stack exchange,提问作者RealRK
相关产品推荐
相关产品推荐

