0

This program works okay on first build.When I disconnect my device and reconnects it,it is showing, bad state:stream has already been listened to, Probably error is generated by stream that listening to Bluetooth characteristic.Whats the work around?

    import 'dart:async';
    import 'dart:convert';
    import 'package:flutter/material.dart';
    import 'package:flutter_blue/flutter_blue.dart';
    import 'package:vibration/vibration.dart';

    StreamSubscription _scanSubscription;
    StreamSubscription _deviceConnection;

    Stream<List<int>> stream;
    List<double> traceDust = List();

    const String CHAR_UUID = "AA:48:F8:CC:07:12";
    const String Device_Name = "myDevice";
    const String CHARACTERISTIC_UUID = "00000000-0111-1000-4000-000000000000";

    BluetoothDeviceState _state;
    Map<DeviceIdentifier, ScanResult> scanResults = new Map();
    List<BluetoothService> services = new List();
    BluetoothCharacteristic characteristic;

    FlutterBlue flutterBlue = FlutterBlue.instance;

    BluetoothDevice device;

    class SearchScreen extends StatefulWidget {
      @override
      _SearchScreenState createState() => _SearchScreenState();
    }

    class _SearchScreenState extends State<SearchScreen> {
      @override
      void initState() {
        super.initState();
        _startScan();
      }

      @override
      void dispose() {
        super.dispose();
        _stopScan();
        _deviceConnection?.cancel();
        _deviceConnection = null;
        device.disconnect();
      }

      _startScan() {
        _scanSubscription =
            flutterBlue.scan(timeout: Duration(seconds: 4)).listen((scanResult) {
          if (CHAR_UUID == scanResult.device.id.toString()) {
            _stopScan();
            _connect(scanResult.device);
            print('connected');
          }
        }, onDone: _stopScan());
      }

      _stopScan() {
        _scanSubscription?.cancel();
        _scanSubscription = null;
      }

      _connect(BluetoothDevice d) async {
        device = d;
        await device.connect(autoConnect: true);
        await device.discoverServices().then((value) {
          setState(() {
            services = value;
          });
        });
        _turnOnCharacterService(services);
      }

      _turnOnCharacterService(List<BluetoothService> ser) async {
        ser.forEach((service) {
          service.characteristics.forEach((character) {
            if (character.uuid.toString() == CHARACTERISTIC_UUID) {
              character.setNotifyValue(!character.isNotifying);
              setState(() {
                stream = character.value;
              });
            }
          });
        });
      }

      String _dataParser(List<int> dataFromDevice) {
        return utf8.decode(dataFromDevice);
      }

      vibrateOnAlert() async {
        if (await Vibration.hasVibrator()) {
          Vibration.vibrate(duration: 1000);
        }
      }



     @override
      Widget build(BuildContext context) {
        return Container(
            child: StreamBuilder<BluetoothDeviceState>(
          stream: device.state,
          initialData: BluetoothDeviceState.connecting,
          builder: (context, snapshot) {
            if (snapshot.data == BluetoothDeviceState.connected) {
              return StreamBuilder<List<int>>(
                  stream: stream,
                  builder: (context, snapshot) {
                    var currentValue;
                    if (snapshot.hasError) {
                      return Text('Error');
                    }
                    if (snapshot.connectionState == ConnectionState.active) {
                      currentValue = _dataParser(snapshot.data);
                      traceDust.add(double.tryParse(currentValue) ?? 0);
                      if (currentValue.toString().compareTo('vibrate') == 0) {
                        vibrateOnAlert();
                      }
                    } else {
                      return Text('disconnected');
                    }
                    print('$currentValue');

                    return Text('connected');
                  });
            }
            return FlatButton(
              color: Colors.white,
              child: Text('reconnecct'),
              onPressed: () {
                setState(() {
                  flutterBlue.startScan(timeout: Duration(seconds: 2));
                });
              },
            );
          },
        ));
      }
    }

PS: Here flat button does nothing.Since connection state is a streambuilder it automatically reconnects and shows error.

  • you can make your stream as a [broadcast](https://api.flutter.dev/flutter/dart-async/StreamController/StreamController.broadcast.html). – hewa jalal Jun 03 '20 at 06:16
  • @hiwajalal How do I implement it in streambuilder?, I tried relpacing `Stream> stream;` to `StreamController> _streamController = StreamController>.broadcast(); Stream> stream = _streamController.stream;` Yet it did not work. – Ananda Padmanabhan Jun 03 '20 at 08:17
  • **This needs to be done inside your class that expose Stream. Not as parameter of StreamBuilder. Since asBroadcastStream internally listen to the original stream to generate the broadcast one, this imply you can't call this method twice on the same stream** this is a comment from this [question](https://stackoverflow.com/questions/51396769/flutter-bad-state-stream-has-already-been-listened-to) explain on how to do it. – hewa jalal Jun 03 '20 at 08:33

0 Answers0