Flutter BLoC:构建()方法中 StreamBuilder 中的 Navigator.pop

Posted

技术标签:

【中文标题】Flutter BLoC:构建()方法中 StreamBuilder 中的 Navigator.pop【英文标题】:Flutter BLoC: Navigator.pop in StreamBuilder in build() method 【发布时间】:2019-09-04 01:06:27 【问题描述】:

我遵循 BLoC 模式并订阅流,并对构建方法中的状态变化做出反应。加载数据后,我想关闭屏幕。

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: const Text('Bloc'),
      ),
      body: SafeArea(
        child: StreamBuilder<UserState>(
          stream: _userBloc.user,
          initialData: UserInitState(),
          builder: (context, snapshot) 
            if (snapshot.data is UserInitState) 
              return _buildInit();
            
            if (snapshot.data is UserDataState) 
              Navigator.pop(context, true);
              return Container();
            
            if (snapshot.data is UserLoadingState) 
              return _buildLoading();
            
          ,
        ),
      ),
    );
   

当我在build() 方法中执行Navigator.pop(context, true); 时,我得到:

I/flutter ( 4360): ══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 4360): The following assertion was thrown while notifying status listeners for AnimationController:
I/flutter ( 4360): setState() or markNeedsBuild() called during build.
I/flutter ( 4360): This Overlay widget cannot be marked as needing to build because the framework is already in the
I/flutter ( 4360): process of building widgets. A widget can be marked as needing to be built during the build phase
I/flutter ( 4360): only if one of its ancestors is currently building. This exception is allowed because the framework
I/flutter ( 4360): builds parent widgets before children, which means a dirty descendant will always be built.
I/flutter ( 4360): Otherwise, the framework might not visit this widget during this build phase.

在 BLoC 模式中处理此类情况的正确方法是什么?

我想出的解决方案之一是开始在initState() 上收听流媒体。在这种情况下,我需要 broadcast() 我的信息流,因为我有 2 个订阅者。

有没有更好的解决方案?

【问题讨论】:

您已经提到了完美的解决方案。 Navigating to a new screen when stream value in BLOC changes的可能重复 【参考方案1】:

我想我已经为你找到了解决方案。 (请检查)

让你的代码看起来像:

Widget build(BuildContext context) 
    // other stuff

    if (snapshot.data is UserDataState) 
      myCallback(() 
        Navigator.pop(context, true);
      );
    

    // other stuff

// after build method (but still in the same class,...) write below method

void myCallback(Function callback) 
    WidgetsBinding.instance.addPostFrameCallback((_) 
      callback();
    );

希望对您有所帮助。试试吧,请在这里报告以帮助其他人!

Source (flutter_bloc Login medium article)

Description

【讨论】:

【参考方案2】:
bool hasPop = false;

  @override
Widget build(BuildContext context) 
  return Scaffold(
    appBar: AppBar(
      title: const Text('Bloc'),
    ),
    body: SafeArea(
      child: StreamBuilder<UserState>(
        stream: _userBloc.user,
        initialData: UserInitState(),
        builder: (context, snapshot) 
          if (snapshot.data is UserInitState) 
            return _buildInit();
          
          if (snapshot.data is UserDataState) 
            if(!hasPop)
               hasPop = true;
               Navigator.pop(context, true);
             
            
            return Container();
          
          if (snapshot.data is UserLoadingState) 
            return _buildLoading();
          
        ,
      ),
    ),
  );
 ```

【讨论】:

请问您能解释一下这段代码吗?谢谢! StreamBuilder 中的每次更改都会触发两次。 Navigator.pop 不能被调用两次。 @GoldenLion 这不是我的问题。所以我不能给你那个。这只是像github.com/felangel/bloc/tree/master/examples/…这样的集团模式 我使用了实现,并为 bloc 的不同状态响应创建了一个子类【参考方案3】:

我可以想象三种可能的解决方案:

1) 在我看来,最好重组您的小部件。据我所知,您想要一个“加载屏幕”。我认为这没有理由必须是它自己的导航项,而不仅仅是另一个小部件。

即。你可以推StreamBuilder 一个吗?升级.. 所以你的 builder 方法看起来像:

if (!snapshot.hasData) 
  return LoadingScreen(snapshot);

// Whatever you do with your data.

2) 我想我个人会创建一个StatefulWidget,在initState() 中手动收听流并手动调用setState()。不需要StreamBuilder

3) 作为一种疯狂的解决方法,您可能可以在构建器中使用Future(() Navigator.of(context).pop(); );。 (有可能您必须使用contextbuild 方法,而不是构建器。但无论如何我都不推荐该解决方案)

【讨论】:

以上是关于Flutter BLoC:构建()方法中 StreamBuilder 中的 Navigator.pop的主要内容,如果未能解决你的问题,请参考以下文章

Dart/Flutter 中 BLoC 模式的最佳实践

什么时候应该在 Flutter 中使用 BLoC 模式?

Flutter Bloc 状态管理

Flutter 状态管理(BloC):无状态与有状态小部件

flutter_bloc :使 initialState 方法异步

Flutter bloc 模式多次重复调用函数