为什么这个 bloc getter 在 null 上被调用?

Why is this bloc getter called on null?

之前我在 main.dart

中初始化我的 PersonBlocProvider
return PersonBlocProvider(
        personBloc: PersonBloc(this._apiInterface),
        child: AlarmBlocProvider(
            alarmBloc: AlarmBloc(this._apiInterface),
            child: EventBlocProvider(
                eventBloc: EventBloc(this._apiInterface),
                child: MaterialApp(
                  title: 'Hat Mobile',
                  theme: ThemeData(
                    primarySwatch: Colors.green,
                  ),
                  home: LoginScreen(),
                )

            )
        )
    );

并在另一个视图中使用 BLOC,如下所示:

class AlarmView extends StatelessWidget {
  Widget build(BuildContext context) {
    final personBlocProvider = PersonBlocProvider.of(context);
    final alarmBlocProvider = AlarmBlocProvider.of(context);

    return
        DefaultTabController(
        length: 4,
        child: Scaffold(
          appBar: AppBar(
            automaticallyImplyLeading: false,
            actions: <Widget>[
              Padding(
                  padding: EdgeInsets.only(top: 10, right: 10),
                  child: Text(StringLiterals.ALARM_TEXT)),
              Padding(
                  padding: EdgeInsets.only(right: 15),
                  child: _BuildSwitch(bloc:  alarmBlocProvider))
            ],
            title: Text(StringLiterals.PAGE_TITLE_ALARM),
            bottom: MyTabBar(),
          ),
          body: TabBarView(
            children: <Widget>[
              _ListPage(StringLiterals.PRESENT, personBlocProvider),
              _ListPage(StringLiterals.SAFE, personBlocProvider),
              _ListPage(StringLiterals.UNKNOWN, personBlocProvider),
              _ListPage(StringLiterals.HOLIDAY, personBlocProvider),
            ],
          ),
        ),
    );
    }
}

这行得通,但应用程序一启动就产生了 BLoC,我意识到我不想要那样。

所以我决定将 BlocProviders 从主文件移动到我的视图文件。

我的主力变成了

              return MaterialApp(
                  title: 'Hat Mobile',
                  theme: ThemeData(
                    primarySwatch: Colors.green,
                  ),
                  home: LoginScreen(),
                );

并查看:

class AlarmView extends StatelessWidget {
  Widget build(BuildContext context) {
    final personBlocProvider = PersonBlocProvider.of(context);
    final alarmBlocProvider = AlarmBlocProvider.of(context);

    return PersonBlocProvider(
        personBloc: PersonBloc(BlueApiMock()),
        child: AlarmBlocProvider(
            alarmBloc: AlarmBloc(BlueApiMock()),
            child: DefaultTabController(
              length: 4,
              child: Scaffold(
                appBar: AppBar(
                  automaticallyImplyLeading: false,
                  actions: <Widget>[
                    Padding(
                        padding: EdgeInsets.only(top: 10, right: 10),
                        child: Text(StringLiterals.ALARM_TEXT)),
                    Padding(
                        padding: EdgeInsets.only(right: 15),
                        child: _BuildSwitch(bloc: alarmBlocProvider))
//                  child: _BuildSwitch(bloc:  AlarmBloc(BlueApiMock())))
                  ],
                  title: Text(StringLiterals.PAGE_TITLE_ALARM),
                  bottom: MyTabBar(),
                ),
                body: TabBarView(
                  children: <Widget>[
                    _ListPage(StringLiterals.PRESENT, personBlocProvider),
                    _ListPage(StringLiterals.SAFE, personBlocProvider),
                    _ListPage(StringLiterals.UNKNOWN, personBlocProvider),
                    _ListPage(StringLiterals.HOLIDAY, personBlocProvider),
                  ],
                ),
              ),
            )
        ));
  }
}

但现在这会导致错误:

I/flutter ( 6448): The following NoSuchMethodError was thrown building AlarmView(dirty):
I/flutter ( 6448): The getter 'personBloc' was called on null.
I/flutter ( 6448): Receiver: null
I/flutter ( 6448): Tried calling: personBloc
I/flutter ( 6448): 
I/flutter ( 6448): When the exception was thrown, this was the stack:
I/flutter ( 6448): #0      Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
I/flutter ( 6448): #1      PersonBlocProvider.of (package:red_photon/alarm/providers/person_bloc_provider.dart:14:30)
I/flutter ( 6448): #2      AlarmView.build (package:red_photon/alarm/views/alarm_view.dart:17:51)

为什么现在为空?

是的,你不能这样做,因为你传递的 context 没有任何 bloc 祖先,而是尝试将 DefaultTabController 包装在 Builder 小部件中并使用该上下文(它将把 bloc 作为 widget 树中的祖先。

示例:

class AlarmView extends StatelessWidget {
  Widget build(BuildContext context) {
    return PersonBlocProvider(
      personBloc: PersonBloc(BlueApiMock()),
      child: AlarmBlocProvider(
        alarmBloc: AlarmBloc(BlueApiMock()),
        child: Builder(
          builder: (context) {
            final personBlocProvider = PersonBlocProvider.of(context);
            final alarmBlocProvider = AlarmBlocProvider.of(context);

            return DefaultTabController(
              length: 4,
              child: Scaffold(
                appBar: AppBar(
                  automaticallyImplyLeading: false,
                  actions: <Widget>[
                    Padding(
                        padding: EdgeInsets.only(top: 10, right: 10),
                        child: Text(StringLiterals.ALARM_TEXT)),
                    Padding(
                        padding: EdgeInsets.only(right: 15),
                        child: _BuildSwitch(bloc: alarmBlocProvider))
                    //                  child: _BuildSwitch(bloc:  AlarmBloc(BlueApiMock())))
                  ],
                  title: Text(StringLiterals.PAGE_TITLE_ALARM),
                  bottom: MyTabBar(),
                ),
                body: TabBarView(
                  children: <Widget>[
                    _ListPage(StringLiterals.PRESENT, personBlocProvider),
                    _ListPage(StringLiterals.SAFE, personBlocProvider),
                    _ListPage(StringLiterals.UNKNOWN, personBlocProvider),
                    _ListPage(StringLiterals.HOLIDAY, personBlocProvider),
                  ],
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

这应该有效。

希望对您有所帮助!