flutter_bluetooth_serial库自动调用cancelDiscovery()问题求助
问题
开发Flutter蓝牙应用时,使用flutter_bluetooth_serial包(版本0.4.0),在initState中调用startDiscovery()后,cancelDiscovery会被无理由立即触发。前两三次运行正常,之后出现如下日志:
D/BluetoothAdapter(15019): startDiscovery(): called by: com.example.bluetooth_app D/FlutterBluePlugin(15019): Canceling discovery (stream closed) D/BluetoothAdapter(15019): cancelDiscovery(): called by: com.example.bluetooth_app
使用Flutter版本3.7,完整代码如下:
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; class FooPage extends StatefulWidget { const FooPage({super.key}); @override State<FooPage> createState() => _FooPageState(); } class _FooPageState extends State<FooPage> { List<BluetoothDiscoveryResult> devices = []; late StreamSubscription<BluetoothDiscoveryResult> _discoveryStreamSubscription; @override void initState() { super.initState(); _startDiscovery(); } void _startDiscovery() { _discoveryStreamSubscription = FlutterBluetoothSerial.instance.startDiscovery().listen( (r) { print('device found'); bool deviceFound = false; devices.forEach((element) { if (element.device.address == r.device.address) { deviceFound = true; } }); if (!deviceFound) { setState(() { devices.add(r); }); } }, ); _discoveryStreamSubscription.onDone(() { setState(() { print('stream closed'); // _isDiscovering = false; }); }); } @override Widget build(BuildContext context) { print(devices); return Scaffold( appBar: AppBar( title: Text("Bluetooth Devices"), ), body: devices.length == 0 ? Center( child: Text('No Nearby devices can be found currently...'), ) : ListView( children: devices .map( (e) => ListTile( title: Text(e.device.name!), subtitle: Text(e.device.type.stringValue), ), ) .toList(), ), ); } }
解决方案
1. 清理StreamSubscription生命周期
当前代码未在页面销毁时取消订阅,多次进入页面会残留旧订阅干扰新发现流程,需在dispose中添加取消逻辑:
@override void dispose() { _discoveryStreamSubscription.cancel(); super.dispose(); }
2. 启动发现前先终止已有任务
系统同一时间只能运行一个蓝牙发现任务,启动新发现前先调用cancelDiscovery()确保无残留进程:
void _startDiscovery() async { // 先终止正在进行的发现 await FlutterBluetoothSerial.instance.cancelDiscovery(); _discoveryStreamSubscription = FlutterBluetoothSerial.instance.startDiscovery().listen( (r) { print('device found'); bool deviceFound = false; devices.forEach((element) { if (element.device.address == r.device.address) { deviceFound = true; } }); if (!deviceFound) { setState(() { devices.add(r); }); } }, ); _discoveryStreamSubscription.onDone(() { setState(() { print('stream closed'); // _isDiscovering = false; }); }); }
3. 确认蓝牙权限配置
Android 12+需要额外的BLUETOOTH_SCAN和BLUETOOTH_CONNECT权限,确保在AndroidManifest.xml中声明:
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
同时需在运行时请求这些权限,可借助permission_handler包实现权限申请逻辑。
4. 避免重复触发发现
页面重建(如屏幕旋转)会再次调用initState,导致重复启动发现任务,可添加状态变量控制:
bool _isDiscovering = false; void _startDiscovery() async { if (_isDiscovering) return; setState(() => _isDiscovering = true); await FlutterBluetoothSerial.instance.cancelDiscovery(); _discoveryStreamSubscription = FlutterBluetoothSerial.instance.startDiscovery().listen( (r) { // 原有设备处理逻辑 }, onDone: () { setState(() { _isDiscovering = false; print('stream closed'); }); }, ); }
内容的提问来源于stack exchange,提问作者Programmerz
相关产品推荐
相关产品推荐

