StreamBuilder перестраивается с предыдущим снимком.данные, а не начальные данные

#flutter #bloc #stream-builder

#flutter #блок #stream-builder

Вопрос:

Я пытаюсь использовать блочную архитектуру в приложении Flutter, и для этой цели я использую StreamController и StreamBuilder. Проблема в том, что StreamBuilder повторяет последний снимок.данные каждый раз, когда они возвращаются. Я вкладываю StreamBuilders. Итак, есть один основной StreamBuilder. Его поток определен в файле mainBloc. initialData — это SomeEvent, а someView возвращается.

someView — это другой StreamBuilder с соответствующим блоком и потоком. initialData — это InitialEvent . При нажатии кнопки SecondEvent добавляется в приемник блоков, и поэтому виджет изменяется. В новом представлении есть еще одна кнопка, и при нажатии на нее mainBloc должен снова показать тот же someView.

Проблема здесь. someView StreamBuilder получает снимок.данные, которые совпадают с последними, но последние не добавляются в приемник снова. Итак, я не понимаю — это то, как должен работать StreamBuilder? Чего я хотел бы добиться, так это этого снимка.вместо этого данные имеют InitialEvent . Возможно ли это? Или, по крайней мере, чтобы не иметь моментального снимка.данные повторяются без запуска.

Приведенный ниже код демонстрирует всю проблему.

 void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  MainBloc mainBloc;
  Bloc bloc;

  MyApp() {
    mainBloc = MainBloc();
    bloc = Bloc();
  }

  Widget mainView() {
    return StreamBuilder<MainEvent>(
      stream: mainBloc.mainStream,
      initialData: SomeEvent(),
      builder: (
        context,
        snapshot,
      ) {
        if (snapshot.hasData) {
          MainEvent event = snapshot.data;
          if (event is SomeEvent) {
            return someView();
          }
          if (event is SomeEventTwo) {
            return someView();
          }
        } else {
          return Container(height: 0, width: 0);
        }
      },
    );
  }

  Widget someView() {
    return StreamBuilder<Event>(
      stream: bloc.stream,
      initialData: InitialEvent(),
      builder: (
        context,
        snapshot,
      ) {
        if (snapshot.hasData) {
          Event event = snapshot.data;
          if (event is InitialEvent) {
            return Column(
              children: [
                Center(
                  child: Text("Initial event"),
                ),
                FlatButton(
                  onPressed: () {
                    bloc.secondEvent();
                  },
                  child: Text("Trigger Second event"),
                  color: Colors.pink,
                ),
              ],
            );
          }
          if (event is SecondEvent) {
            return Center(
              child: FlatButton(
                child: Text("Show same screen again"),
                onPressed: () {
                  bloc.dispose();
                  bloc = Bloc();
                  mainBloc.showScreenTwo();
                },
                color: Colors.blue,
              ),
            );
          }
        } else {
          return Container(height: 0, width: 0);
        }
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          backgroundColor: Colors.grey,
        ),
        body: mainView(),
      ),
    );
  }
}
 

Это блоки:
MainBloc:

 class MainBloc {
  StreamController<MainEvent> _mainStreamController;

  StreamSink<MainEvent> get _mainSink => _mainStreamController.sink;

  Stream<MainEvent> get mainStream => _mainStreamController.stream;

  MainBloc() {
    _mainStreamController = StreamController<MainEvent>();
  }

  void showScreen() {
    _mainSink.add(SomeEvent());
  }

  void showScreenTwo() {
    _mainSink.add(SomeEventTwo());
  }
}

abstract class MainEvent {}

class SomeEvent extends MainEvent {}

class SomeEventTwo extends MainEvent {}
 

Блок:

 class Bloc {
  StreamController<Event> _controller;

  StreamSink<Event> get _sink => _controller.sink;

  Stream<Event> get stream => _controller.stream;

  Bloc() {
    _controller = StreamController<Event>();
  }

  void secondEvent() async {
    _sink.add(SecondEvent());
  }

  dispose() {
    _controller.close();
  }
}

abstract class Event {}

class InitialEvent extends Event {}

class SecondEvent extends Event {}
 

Ответ №1:

Не тестировал, но, возможно, попробуйте за пределами вашего MaterialApp :

 class MainView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<MainEvent>(
      stream: mainBloc.mainStream,
      initialData: SomeEvent(),
      builder: (
        context,
        snapshot,
      ) {
        if (snapshot.hasData) {
          MainEvent event = snapshot.data;
          if (event is SomeEvent) {
            return someView();
          }
          if (event is SomeEventTwo) {
            return someView();
          }
        } else {
          return Container(height: 0, width: 0);
        }
      },
    );
  }
}
 

вместо Widget someView(){ return ... }

Поведение setState иногда работает по-другому, если вы используете собственный метод сборки вместо объявления StatelessWidget.