今回の件の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();
}
}
その他
勉強不足でStreamController
とBehaviorSubject
の違いをまだ理解できておりません。
ご存知の方いましたら、教えていただけますと幸甚です。
@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に流れてきます。
参考記事