После использования навигатора на странице tabBarView данные теряются - PullRequest
0 голосов
/ 03 апреля 2019

У меня есть домашняя страница с tabBarView с 2 страницами, дом и избранное.На домашней странице есть gridview, чьи ячейки заполнены streambuilder.При нажатии они используют Навигатор для перенаправления на страницу сведений для этой ячейки.Я могу вкладывать между 2 вкладками.После перехода на страницу сведений (с домашней страницы) и возвращения домой gridView правильно отображает свои данные.Но после этого, если я перейду на страницу избранного и вернусь домой, данные gridView будут потеряны.

Я попытался AutomaticKeepAliveClientMixin и wantKeepAlive = true, как рекомендуется для SO.

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

Переход со страницы сведений на домашнюю страницу перестраивает домашнюю страницустраница, и это тоже хорошо, как данные отображаются.Только если после этого я перейду на вкладку «Избранное» и вернусь снова, проблема возникнет.

Я использую шаблон блока и имею ссылку на блок провайдера в домашнем виджете.Он передает это в gridView.

Я использую стандартные tabBarView и Navigator в SliverAppBar.


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MovieProvider(
      euCollBloc: EuThemeCollectionBloc(API()),
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(),

        home: MyHomePage(),
      ),
    );
  }
}


body: TabBarView(
          children: <Widget>[
            PageOne(),

            PageTwo(),

          ],

bottom: TabBar(
                  tabs: <Widget>[
                    Tab(
                      text: "Home",
                      icon: Icon(Icons.home),
                    ),
                    Tab(
                      text: "Favorites",
                      icon: Icon(Icons.favorite),
                    ),

                  ],
                  controller: _tabController,
                ))

.......

Навигатор, используемый в виджете PageOne:

.......

return GridView.builder(
              gridDelegate:
                  SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
              itemCount: snapshot.data.length,
              itemBuilder: (context, index) => GestureDetector(
                    onTap: () {
                      Navigator.of(context).push(MaterialPageRoute(
                        builder: (context) => EuroCard(
                              preview: snapshot.data[index].preview ?? "",
                              title: snapshot.data[index].title,
                              description: snapshot.data[index].description,
                            ),
                      ));
                    },
                    child: Card(
.......

Использование (возможно, слишком продвинутого для меня) провайдера и блочного кода из учебника по тензору на YouTube.

Блок:

class EuThemeCollectionBloc {
  final API api;

  Stream<List<EuThemeCollection>> _results = Stream.empty();
  Stream<String> _log = Stream.empty();

  ReplaySubject<String> _query = ReplaySubject<String>();

  Stream<String> get log => _log;
  Stream<List<EuThemeCollection>> get results => _results;
  Sink<String> get query => _query;

  EuThemeCollectionBloc(this.api) {
    _results = _query.distinct().asyncMap(api.get).asBroadcastStream();

    _log = Observable(results)
        .withLatestFrom(_query.stream, (_, query) => 'Results for $query')
        .asBroadcastStream();
  }

  void dispose() {
    _query.close();
  }
}


провайдер:

class MovieProvider extends InheritedWidget {
  final EuThemeCollectionBloc euCollBloc;

  @override
  bool updateShouldNotify(InheritedWidget oldWidget) => true;

  static EuThemeCollectionBloc of(BuildContext context) =>
      (context.inheritFromWidgetOfExactType(MovieProvider) as MovieProvider)
          .euCollBloc;

  MovieProvider({Key key, EuThemeCollectionBloc euCollBloc, Widget child})
      : this.euCollBloc = euCollBloc ?? EuThemeCollectionBloc(API()),
        super(child: child, key: key);
}

Я пытался использовать BehaviorSubject, но затем я получаю ошибку во время выполнения, ссылаясь на поток запросов в mainстраница:

Ошибка: получатель 'euCollBloc' не определен для класса 'EuroCard'.- «EuroCard» из пакета «bloc_example / euroCard.dart» («lib / euroCard.dart»).Попробуйте исправить имя с именем существующего получателя или определить получатель или поле с именем 'euCollBloc'.

ИСПРАВЛЕНО: Мне нужно было добавить super.build (context) к виджету PageOne (GridView) - itрасширяет состояние с помощью AutomaticKeepAliveClientMixin, поэтому его необходимо переопределить.Извините, изначально даже не публиковал раздел о виновниках.


class _PageOneState extends State<PageOne>  with
AutomaticKeepAliveClientMixin<PageOne>{
  @override
  bool get wantKeepAlive => true;
  Widget build(BuildContext context){
   super.build(context);
  var euCollBloc = MovieProvider.of(context);






1 Ответ

0 голосов
/ 04 апреля 2019

Кажется, я исправил это с помощью простого setState (() {euCollBloc = euCollBloc)} в виджете PageOne (GridView).

Теперь я могу сделать то, что не мог сделать раньше: загрузить домашнюю вкладку, которая отображает Gridview с ячейками данных, затем перейти на страницу сведений о ячейке и вернуться домой, перейти на страницу избранного и снова вернуться на главную страницу. и данные по-прежнему отображаются.

Что касается того, почему это исправляет, я не уверен. Я думал, что шаблон провайдера защищает от подобных состояний.

...