Flutter: Плохое состояние: Stream уже прослушали


    class MyPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return DefaultTabController(
          length: 2,
          child: new Scaffold(
            appBar: TabBar(
              tabs: [
                Tab(child: Text("MY INFORMATION",style: TextStyle(color: Colors.black54),)),
                Tab(child: Text("WEB CALENDER",style: TextStyle(color: Colors.black54),)),
              ],
            ),
            body:PersonalInformationBlocProvider(
              movieBloc: PersonalInformationBloc(),
              child: TabBarView(
                children: [
                  MyInformation(),
                  new SmallCalendarExample(),
                ],
              ),
            ),
          ),
        );
      }
    }

    class MyInformation extends StatelessWidget{
      // TODO: implement build
      var deviceSize;

      //Column1
      Widget profileColumn(PersonalInformation snapshot) => Container(
        height: deviceSize.height * 0.24,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                Container(
                  decoration: BoxDecoration(
                    borderRadius:
                    new BorderRadius.all(new Radius.circular(50.0)),
                    border: new Border.all(
                      color: Colors.black,
                      width: 4.0,
                    ),
                  ),
                  child: CircleAvatar(
                    backgroundImage: NetworkImage(
                        "http://www.binaythapa.com.np/img/me.jpg"),
                    foregroundColor: Colors.white,
                    backgroundColor: Colors.white,
                    radius: 40.0,
                  ),
                ),
                ProfileTile(
                  title: snapshot.firstName,
                  subtitle: "Developer",
                ),
                SizedBox(
                  height: 10.0,
                ),
              ],
            )
          ],
        ),
      );
      Widget bodyData(PersonalInformation snapshot) {
        return SingleChildScrollView(
            child: Column(
              children: <Widget>[
                profileColumn(snapshot)
              ],
            ),
        );
      }


      @override
      Widget build(BuildContext context) {
        final personalInformationBloc = PersonalInformationBlocProvider.of(context);

        deviceSize = MediaQuery.of(context).size;
        return StreamBuilder(
            stream: personalInformationBloc.results,
            builder: (context,snapshot){
              if (!snapshot.hasData)
                return Center(
                  child: CircularProgressIndicator(),
                );
              return bodyData(snapshot.data);
            }
        );
      }
    }


Я использую Bloc Pattern для извлечения данных из Rest API (только что вызвал весь объект из json и только проанализировал имя пользователя). Страница состоит из двух вкладок MyIformation и SmallCalendar. Когда приложение запускается, данные выбираются правильно, и все хорошо. Когда я перехожу на вкладку 2 и возвращаюсь к вкладке 1, все экраны на вкладке 1 переходят в красный цвет, показывая ошибку: Bad state: Stream has already been listened to.

Ответы

Ответ 1

Проблема заключалась в том, что они не выбрали контроллеры в блоке.

  void dispose() {
    monthChangedController.close();
    dayPressedController.close();
    resultController.close();
  }

Ответ 2

Вы должны использовать следующее.

StreamController<...> _controller = StreamController<...>.broadcast();

Ответ 3

Наиболее распространенную форму Stream можно слушать только один раз за раз. Если вы попытаетесь добавить нескольких слушателей, это будет

Плохое состояние: поток уже прослушали

Чтобы предотвратить эту ошибку, выведите широковещательный Stream. Вы можете конвертировать свой поток в эфир, используя myStream.asBroadcastStream

Это необходимо сделать внутри вашего класса, которые выставляют Stream. Не как параметр StreamBuilder. Поскольку asBroadcastStream внутренне прослушивает исходный поток для генерации широковещательной передачи, это означает, что вы не можете дважды вызвать этот метод в одном потоке.

Ответ 4

В моем случае я получал эту ошибку, потому что одна и та же строка кода myStream.listen() вызывалась дважды в одном и том же виджете в одном и том же потоке. Видимо, это запрещено!

Для меня исправлено то, что я создал контроллер потока в качестве контроллера потока вещания:

var myStreamController = StreamController<bool>.broadcast();

И

использовать поток в качестве вещательного потока:

myStreamController.stream.asBroadcastStream().listen(onData);

Ответ 5

У меня была такая же проблема, когда я использовал результат Observable.combineLatest2 для StreamBuilder в Drawer:

flutter: плохое состояние: поток уже прослушан.

Как по мне, лучшее решение - добавить результат этого объединения в новый BehaviorSubject и прослушать новый.

Не забудь послушать старую !!!

class VisitsBlocc extends Object {
    Map<Visit, Location> visitAndLocation;

    VisitsBloc() {
        visitAndLocations.listen((data) {
            visitAndLocation = data;
        });
    }

    final _newOne = new BehaviorSubject<Map<Visit, Location>>();

    Stream<Map<Visit, Location>> get visitAndLocations => Observable.combineLatest2(_visits.stream, _locations.stream, (List<vis.Visit> visits, Map<int, Location> locations) {
        Map<vis.Visit, Location> result = {};

        visits.forEach((visit) {
            if (locations.containsKey(visit.skuLocationId)) {
                result[visit] = locations[visit.skuLocationId];
            }
        });

        if (result.isNotEmpty) {
            _newOne.add(result);
        }
    });
}

Я не использовал .broadcast потому что это замедлило мой интерфейс.

Ответ 6

Просто подвести итог:

Основное отличие состоит в том, что broadcast() создает a Stream для прослушивания для нескольких источников, но его необходимо прослушивать, по крайней мере, для одного источника, чтобы начать излучать элементы.

Поток должен быть инертным до тех пор, пока подписчик не начнет слушать его (используя обратный вызов [onListen], чтобы начать генерировать события).

asBroadcastStream превращает существующий Stream в мульти-прослушиваемый, но его не нужно слушать, чтобы начать излучать, так как он вызывает onListen() под капотом.

Ответ 7

Вы можете использовать broadcast, который позволяет прослушивать поток более одного раза, но также предотвращает прослушивание прошлых событий:

Широковещательные потоки не буферизуют события, когда нет прослушивателя.

Лучшим вариантом является использование BehaviorSubject из класса пакета rxdart в качестве StreamController. BehaviorSubject это:

Специальный StreamController, который захватывает последний элемент, который был добавлен в контроллер, и отправляет его в качестве первого элемента любому новому слушателю.

Использование так же просто, как:

StreamController<...> _controller = BehaviorSubject();