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(); );
。 (有可能您必须使用context
的build
方法,而不是构建器。但无论如何我都不推荐该解决方案)
【讨论】:
以上是关于Flutter BLoC:构建()方法中 StreamBuilder 中的 Navigator.pop的主要内容,如果未能解决你的问题,请参考以下文章