Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
821 views
in Technique[技术] by (71.8m points)

flutter - "Bad state: Stream has already been listened to" occurs when I visit screen multiple times

I'm using flutter_bluetooth_serial library and in initState() function I'm using listen to call a function. It's working fine when the app initially starts but when I visit this screen for the second time on the app I get a red screen saying "Bad state: Stream has already been listened to".

I'm new to flutter so please provide the exact code that can help me resolve this issue.

 @override
  void initState() {
    super.initState();

    widget.connection.input.listen(_onDataReceived).onDone(() {
      // Example: Detect which side closed the connection
      // There should be `isDisconnecting` flag to show are we are (locally)
      // in middle of disconnecting process, should be set before calling
      // `dispose`, `finish` or `close`, which all causes to disconnect.
      // If we except the disconnection, `onDone` should be fired as result.
      // If we didn't except this (no flag set), it means closing by remote.
      if (isDisconnecting) {
        print('Disconnecting locally!');
      } else {
        print('Disconnected remotely!');
      }
      if (this.mounted) {
        setState(() {});
      }
    });
  }
question from:https://stackoverflow.com/questions/65898914/bad-state-stream-has-already-been-listened-to-occurs-when-i-visit-screen-mult

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Try to override dispose() method of the state and cancel subscription within it. To do that you need to save subscription in a variable:

  StreamSubscription _subscription;

  @override
  void initState() {
    super.initState();
    _subscription = widget.connection.input.listen(_onDataReceived, onDone: () {
      ...
    });
  }

  override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }

Edit

If you need to subscribe to the connection.input multiple times across the app - you can transform it to broacast stream and subscribe for it. It should help. Like this:

final broadcastInput = connection.input.asBroadcastStream();

But if you need to use connection only in this widget I would recommend you to keep it inside state (not widget) and close it on dispose. It would be better lifecycle control solution.

  BluetoothConnection _connection;

  @override
  void initState() {
    super.initState();
    _initConnection();
  }

  Future<void> _initConnection() async {
    _connection = await BluetoothConnection.toAddress(address);
    /// Here you can subscribe for _connection.input
    ...
  }

  @override
  void dispose() {
    connection;
    super.dispose();
  }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...