【问题标题】:flutter bloc pattern navigation back results in bad state颤动块模式导航返回导致状态不佳
【发布时间】:2019-03-28 10:25:26
【问题描述】:

我有一个关于颤振的 bloc plattern 的问题/问题。 目前,我正在像这样启动我的应用程序

class _MyAppState extends State<MyApp> {

@override
  Widget build(BuildContext context) {        
    return BlocProvider(
        bloc: MyBloc(),
        child: MaterialApp(
          title: "MyApp",
          home: MyHomePage(),    
          routes: {
            '/homePage': (context) => MyHomePage(),
            '/otherPage': (context) => OtherPage(),
            '/otherPage2': (context) => OtherPage2(),
            ...
          },
        ));

这样我就可以像检索/访问 myBloc 一样

myBloc = BlocProvider.of(context) as MyBloc;

以及状态所代表的数据

BlocBuilder<MyBlocEvent, MyObject>(
    bloc: myBloc,
    builder: (BuildContext context, MyObject myObject) {         
     ....
     var t = myObject.data;
     ....
     myBloc.onFirstEvent();
     ...
 }; 

在我需要的地方。

MyBloc 是这样实现的:

abstract clas MyBlocEvent {}
class FirstEvent extends MyBlocEvent {}
class SecondEvent extends MyBlocEvent {}

class MyBloc extends Bloc<MyBlocEvent , MyObject>

void onFirstEvent()
{
  dispatch(FirstEvent());
}

void onSecondEvent()
{
  dispatch(SecondEvent());
}

@override
Stream<MyObject> mapEventToState( MyObject state, MyBlocEvent event) async* {
if (event is FirstEvent) {
    state.data = "test1";
}
else if (event is SecondEvent) {
    state.otherData = 5;
}
    yield state;
}

我现在遇到的问题是,一旦我改变状态值并调用

Navigator.pop(context)

要返回当前堆栈,我无法再更改任何状态,因为底层流似乎已关闭。它失败并显示消息:

抛出了另一个异常:Bad state: Cannot add new events after call close"

现在这只发生在我调用 pop 之后。如果我只推送新屏幕,我可以愉快地更改状态数据而不会出现任何问题。

我是否在此处的导航方面做错了什么,或者关于颤振或 bloc 模式本身还有什么我没有发现的吗?

【问题讨论】:

  • 我相信它是使用的 BlocProvider,我刚刚切换到 pub.dartlang.org/packages/provider 并且这不再发生在我身上......我们会看到。不过希望得到更好的解释。

标签: stream navigation flutter


【解决方案1】:

错误状态:调用关闭后无法添加新事件

此错误表示您在调用StreamController 之后调用add 调用了close

 var controller = StreamController<int>();
 controller.close();
 controller.add(42); // Bad state: Cannot add new events after calling close

这可能与您在 dispose 方法中调用“错误”小部件中的 close 有关。

一个好的经验法则是从不在创建它的小部件之外处置/关闭一个对象。这样可以确保您不能使用已处置的对象。

【讨论】:

  • 为了修复它,我不得不删除 dispose 方法
【解决方案2】:

希望这对您的调试有所帮助。

应用的导航取决于您的小部件设计。

我使用无状态小部件并使用 bloc 的数据呈现视图。

每当我导航到另一个页面时,我都会弹出当前小部件并导航到下一个小部件。

下一个无状态小部件声明 bloc, 那么在你后续的无状态小部件中应该包含像MyBloc.dispatch(event(param1: value1, param2: value2));这样的调用

在 MyBloc 中,您需要设置包含最终值的状态工厂;

@override
Stream<MyObject> mapEventToState( MyObject state, MyBlocEvent event) async* {
if (event is FirstEvent) {
    // set it in the state, so this code is omitted
    // state.data = "test1";
    // add this
    yield state.sampleState([], "test1");
}
else if (event is SecondEvent) {
    // state.otherData = 5;
    yield state.sampleState([], 5);
} else {
    yield state.sampleState([], null);
}

MyObjectState 需要这样设置,

class MyObjectState {
  final List<Bar> bars;
  final String Foo;

  const MyObjectState(
      {this.bars,
      this.foo,
  });

  factory MyObjectState.sampleState(List<Bar> barList, String value1) {
    return MyObjectState(bars: barList, foo: message);
  }
}

这样无状态小部件可以像这样使用块 MyBloc.currentState.sampleState.foo

您可以尝试运行 Felix Angelov 的颤振项目。 Login Flow Example

【讨论】:

  • 感谢您对这么旧的票证的回答,没想到此时会得到任何回应 :) 我使用导航器来保存访问页面的历史记录,所以我没有自己实现所有这些,所以只需弹出当前页面并推送下一个页面就需要我这样做。 Felix Angelov 的示例表单非常简单(很遗憾,就像我发现的许多一样),也不会提供历史记录。我将在下一个项目中尝试您的建议,我将在其中使用 bloc 模式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-01
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 2022-06-18
  • 1970-01-01
相关资源
最近更新 更多