如何在initState方法中访问Flutter Bloc?

14
在下面显示的代码中,在获取BuildContext对象后,dispatch事件从build方法内部调用。如果我希望在initState方法本身开始处理时分派事件怎么办?
如果我使用didChangeDependencies方法,那么我会得到以下错误: BlocProvider.of()使用不包含FileManagerBloc类型Bloc的上下文进行调用。如何解决?
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: BlocProvider<FileManagerBloc>(
          builder: (context)=>FileManagerBloc(),
          child: SafeArea(
      child: Container(
          child: Column(
            children: <Widget>[
              Container(color: Colors.blueGrey, child: TopMenuBar()),
              Expanded(
                child: BlocBuilder<FileManagerBloc,FileManagerState>(
                  builder: (context , state){
                    return GridView.count(
                      scrollDirection: Axis.vertical,
                      physics: ScrollPhysics(),
                      crossAxisCount: 3,
                      crossAxisSpacing: 10,
                      children: getFilesListWidget(context , state),
                    );
                  },
                ),
              )
            ],
          ),
      ),
    ),
        ));
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  void didChangeDependencies() {
    logger.i('Did change dependency Called');
    final FileManagerBloc bloc = BlocProvider.of<FileManagerBloc>(context) ;
    Messenger.sendGetHomeDir()
        .then((path) async {
      final files = await Messenger.sendListDir(path);
        bloc.dispatch(SetCurrentWorkingDir(path)) ;
        bloc.dispatch(UpdateFileSystemCacheMapping(path , files)) ;
    });
  }
3个回答

9
问题在于你正在BlocProvider中初始化FileManagerBloc的实例,这当然是无法从父部件访问的。我知道这有助于自动清理Bloc,但如果你想在initStatedidChangeDependencies中访问它,则必须像这样在父级别进行初始化:
FileManagerBloc _fileManagerBloc;

@override
void initState() {
  super.initState();
  _fileManagerBloc= FileManagerBloc();
  _fileManagerBloc.dispatch(LoadEducation());
}

@override
  Widget build(BuildContext context) {
    return Scaffold(
        body: BlocProvider<FileManagerBloc>(
          builder: (context)=> _fileManagerBloc,
          child: SafeArea(
      child: Container(
          child: Column(
            children: <Widget>[
              Container(color: Colors.blueGrey, child: TopMenuBar()),
              Expanded(
                child: BlocBuilder<FileManagerBloc,FileManagerState>(
                  builder: (context , state){
                    return GridView.count(
                      scrollDirection: Axis.vertical,
                      physics: ScrollPhysics(),
                      crossAxisCount: 3,
                      crossAxisSpacing: 10,
                      children: getFilesListWidget(context , state),
                    );
                  },
                ),
              )
            ],
          ),
      ),
    ),
        ));
  }

  @override
  void dispose() {
    _fileManagerBloc.dispose();
    super.dispose();
  }

  @override
  void didChangeDependencies() {
    logger.i('Did change dependency Called');
    Messenger.sendGetHomeDir()
        .then((path) async {
      final files = await Messenger.sendListDir(path);
        _fileManagerBloc.dispatch(SetCurrentWorkingDir(path)) ;
        _fileManagerBloc.dispatch(UpdateFileSystemCacheMapping(path , files)) ;
    });
  }

如果FileManagerBloc在祖先Widget处提供/初始化,那么它就可以通过BlocProvider.of<CounterBloc>(context);在此级别轻松访问。


1

解决方案: 步骤1:需要在Bloc类上应用单例模式。

class AuthBloc extends Bloc<AuthEvent, AuthState> {
  static AuthBloc? _instance;
  static AuthBloc get instance {
    if (_instance == null) _instance = AuthBloc();
    return _instance!;
  }
  ....
  ....

第二步:在 main.dart 中使用 AuthBloc.instance 作为 Provider
void main() async {
  runApp(MultiBlocProvider(
    providers: [
      BlocProvider(
        create: (context) => AuthBloc.instance,
      ),
      ...
      ...
    ],
    child: App(),
  ));
}

现在您可以在没有上下文的情况下使用Bloc

  1. 您可以通过从initState或任何地方获取AuthBloc.instance.state来获得状态
  2. 您可以通过AuthBloc.instance.add(..)从任何地方添加事件
  3. 您还可以非常简单地从另一个BlocB中调用BlocA

1
您可以在didChangeDependencies方法中使用它,而不是initState示例
 @override
  void didChangeDependencies() {
    final CounterBloc counterBloc = BlocProvider.of<CounterBloc>(context);
    //do whatever you want with the bloc here.
    super.didChangeDependencies();
  }

BlocProvider.of<CounterBloc>(context) 报错了,我已经更新了我的问题,请建议修复方法。 - Natesh bhat
不确定为什么这个被踩了。这是访问 bloc 的合法方式。我在 didChangeDependencies 中使用它。在父部件中,我有 BlocProvider,所以我可以在子部件中访问 bloc。我使用它来触发事件,每当我导航到特定视图时都会使用 counterBloc.add(...) - user3056783
在didChangeDependencies中触发块事件是非常不好的做法 - 特别是在复杂小部件中,要检查这可以触发多少次。在这里使用上下文是安全的,但不一致。 - Simon Sot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接