【问题标题】:Flutter BLoC: Navigator.pop in StreamBuilder in build() methodFlutter BLoC:构建()方法中 StreamBuilder 中的 Navigator.pop
【发布时间】: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 个订阅者。

有没有更好的解决方案?

【问题讨论】:

标签: flutter bloc


【解决方案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 方法,而不是构建器。但无论如何我都不推荐该解决方案)

    【讨论】:

      猜你喜欢
      • 2019-12-26
      • 2020-07-21
      • 2020-12-30
      • 2021-06-16
      • 2019-11-03
      • 2019-10-11
      • 2023-03-24
      • 2020-07-30
      • 1970-01-01
      相关资源
      最近更新 更多