4
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Organization

【Flutter】バグ解決: Bad state: Stream has already been listened to.

今回の件のGitHubはこちら

現象

StreamControllerを使ってBLoCパターンでstatement管理をしていたが、TabBarViewを追加して、
Tabを切り替えて、再度同じタブに復帰した際に画面の表示が崩れるようになりました。

その際のerrorがこちら。

Bad state: Stream has already been listened to.

解決策

StreamControllerではなく、BehaviorSubjectを使用することで解消

元のソースコード

エラー解消前
import 'dart:async';

class CounterBloc {
  // input
  final _actionController = StreamController<bool>();
  Sink<void> get changeCountAction => _actionController.sink;

  //output
  final _countController = StreamController<int>();
  Stream<int> get count => _countController.stream;

  int _count = 0;

  CounterBloc() {
    _actionController.stream.listen((isPlus) {
      if (isPlus) {
        _count++;
      } else {
        _count--;
      }
      _countController.sink.add(_count);
    });
  }

  void dispose() {
    _actionController.close();
    _countController.close();
  }
}
エラー解消後
import 'dart:async';
import 'package:rxdart/rxdart.dart';

class CounterBloc {
  // input
  final _actionController = BehaviorSubject<bool>();
  Sink<void> get changeCountAction => _actionController.sink;

  //output
  final _countController = BehaviorSubject<int>();
  Stream<int> get count => _countController.stream;

  int _count = 0;

  CounterBloc() {
    _actionController.stream.listen((isPlus) {
      if (isPlus) {
        _count++;
      } else {
        _count--;
      }
      _countController.sink.add(_count);
    });
  }

  void dispose() {
    _actionController.close();
    _countController.close();
  }
}

その他

勉強不足でStreamControllerBehaviorSubjectの違いをまだ理解できておりません。
ご存知の方いましたら、教えていただけますと幸甚です。

@ntaooさんより、メッセージいただきました。

StreamController: StreamのController。
デフォルトではSingle Subscription Streamなので、一度listenしたあともう一度listenするとそのエラーが発生します。

BehaviorSubject: Broadcast Stream Controller に、Stream Elementのcacheという振る舞いを追加したもの。
Broadcast Stream Controllerが制御するStreamは何度でもlistenできますがlistenerリソースの管理をしないとリソースリークする可能性があります。
ListenしたタイミングでBehaviorSubjectから最新のcacheがlistenerに流れてきます。

参考記事

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
4
Help us understand the problem. What are the problem?