You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 23:07:37