导航到另一个 pageView 或任何 View 时,Bloc 小部件 reftech 数据(重建)

Posted

技术标签:

【中文标题】导航到另一个 pageView 或任何 View 时,Bloc 小部件 reftech 数据(重建)【英文标题】:Bloc widgets reftech data (rebuild) when navigating to another pageView or any View altogether 【发布时间】:2020-09-27 22:13:24 【问题描述】:

上下文:我有一个应用程序,它有一个 PageView 使用 BottomNavigationBar 在五个屏幕之间导航,一个页面正在使用 Bloc 模式(几乎所有页面都将使用 Bloc在未来的版本中)这些 Bloc 正在从后端服务获取数据,以使用获取的数据填充 UI。

问题:在小部件树的任何级别的页面之间导航时。 Bloc 小部件“重置”并从存储库中重新获取数据。

如下图所示:

Widget 树如下:

main.dart home.dart timeline.dart(屏幕截图所示)

尝试过的解决方案:我将AutomaticKeepAliveClientMixin 添加到页面类和其他页面,但它没有完成这项工作。

这是上面屏幕截图中显示的页面的构建方法的代码

   @override
  Widget build(BuildContext context) 

    super.build(context);

    return DefaultTabController(
      length: 4,
      child: Scaffold(
        backgroundColor: Colors.white,
        appBar: _builAppBarWithTabs(),
        body: Center(
          child: ConstrainedBox(
            constraints: BoxConstraints(maxWidth: 1200),
            child: ListView(
              scrollDirection: Axis.vertical,
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.only(bottom: 150),
                  child: Container(
                    height: 800,
                    child: CustomScrollView(
                      scrollDirection: Axis.vertical,
                      slivers: <Widget>[
                        SliverToBoxAdapter(
                          child: MasonryGrid(
                            column: getResponsiveColumnNumber(context, 1, 2, 6),
                            children: <Widget>[
                              // First Bloc
                              BlocProvider(
                                create: (context) 
                                  BrandBloc(repository: _brandRepository);
                                ,
                                child: Container(
                                  width: 200,
                                  alignment: Alignment.center,
                                  height: 80,
                                  child: BrandScreen(
                                    brandBloc: context.bloc(),
                                  ),
                                ),
                              ),
                              CategoryScreen(
                                // Second Bloc
                                categoryBloc: CategoryBloc(
                                  repository: context.repository(),
                                ),
                              ),
                              Container(
                                width: 200,
                                alignment: Alignment.center,
                                height: 330,
                                child: _buildFeaturedItemsList(),
                              ),
                              Placeholder(
                                strokeWidth: 0,
                                color: Colors.white,
                              )
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                ),


              ],
            ),
          ),
        ),
      ),
    );
  

here 是类timeline.dart 的代码

here 是包含BottomNavigationBar 类的home.dart 类的代码

问题:如何在每次小部件重建时阻止块获取数据?

【问题讨论】:

【参考方案1】:

我终于明白了这个问题 事实证明,这与bloc 无关,而是与PageView 有关的问题。

我用PageStorage 小部件包装了PageView,如下所示:

final PageStorageBucket bucket = PageStorageBucket(); //PageStorageBucket
  static List<Widget> pages = [
    Timeline(pageController: pageController, key: PageStorageKey('timeline')),
    Search(key: PageStorageKey('search')),
    LikeScreen(key: PageStorageKey('like')),
    CartScreen(key: PageStorageKey('cart')),
    storageService.getFromDisk('api_token') != null
        ? ProfileScreen(key: PageStorageKey('profile'))
        : AuthChooserScreen(key: PageStorageKey('auth')),
  ];
  @override
  Widget build(BuildContext context) 
    super.build(context);
    return SafeArea(
      top: true,
      bottom: true,
      child: Scaffold(
        backgroundColor: Colors.white,
        key: _scaffoldKey,
        //Wrapped  PageView with PageStorage
        body: PageStorage(
          bucket: bucket,
          child: PageView(
            children: pages,
            controller: pageController,
            onPageChanged: onPageChanged,
            physics: NeverScrollableScrollPhysics(),
          ),
        ),
        bottomNavigationBar: _buildBottomNavigationBar(),
      ),
    );
  

每个页面都分配有一个 PageStorageKey,用于保存和恢复比小部件寿命更长的值

感谢这篇出色的媒体文章完美地解释了它: Keeping State with the Bottom Navigation Bar in Flutter

【讨论】:

【参考方案2】:

您以错误的方式使用 BlocProvider 小部件 相反,您应该将 BlocProvider 提取到在页面之间导航时不会重新构建的上层“如果您在整个应用程序中使用此块,则可能是 MaterialApp 小部件”。 然后使用 BlocBuilder 或 BlocConsumer 将现有的 Bloc 实例提供给子小部件,并在 bloc 状态更改时自动重建。 BlocBuilder 官方文档: https://bloclibrary.dev/#/flutterbloccoreconcepts?id=blocbuilder

【讨论】:

以上是关于导航到另一个 pageView 或任何 View 时,Bloc 小部件 reftech 数据(重建)的主要内容,如果未能解决你的问题,请参考以下文章

使用底部导航栏颤动保存 PageView 内每个页面的状态

带有 PageView 的 Flutter 底部导航栏

登录成功后将视图导航到另一个视图

当我导航到另一个屏幕时,视频继续播放

将核心数据对象从 DetailViewController 传递到另一个 View Controller

SwiftUI PageView iOS 13 - 导航链接未按预期工作