'how to access flutter bloc in the initState method?

In the code shown below , the dispatch event is called from within the build method after getting the BuildContext object. What if I wish to do is to dispatch an event during processing at the start of the page within the initState method itself ?

If I use didChangeDependencies method , then I am getting this error : BlocProvider.of() called with a context that does not contain a Bloc of type FileManagerBloc. how to fix this?

  @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)) ;
    });
  }


Solution 1:[1]

The problem is that you are initializing the instance of FileManagerBloc inside the BlocProvider which is, of course inaccessible to the parent widget. I know that helps with automatic cleanup of the Bloc but if you want to access it inside initState or didChangeDependencies then you have to initialize it at the parent level like so,

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)) ;
    });
  }

alternatively, if FileManagerBloc was provided/initialized at a grandparent Widget then it could easily be accessible at this level through BlocProvider.of<CounterBloc>(context);

Solution 2:[2]

you can use it in didChangeDependencies method rather than initState.

Example

 @override
  void didChangeDependencies() {
    final CounterBloc counterBloc = BlocProvider.of<CounterBloc>(context);
    //do whatever you want with the bloc here.
    super.didChangeDependencies();
  }

Solution 3:[3]

Solution: Step 1: need apply singleton pattern on Bloc class

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

Step 2: use AuthBloc.instance on main.dart for Provider

void main() async {
  runApp(MultiBlocProvider(
    providers: [
      BlocProvider(
        create: (context) => AuthBloc.instance,
      ),
      ...
      ...
    ],
    child: App(),
  ));
}

Now you can use Bloc without context

  1. you can get state by AuthBloc.instance.state from initState or anywhere
  2. you can add event from anywhere by AuthBloc.instance.add(..)
  3. you also call BlocA from another BlocB very simple

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Oliver Atienza
Solution 2 Karim Elghamry
Solution 3 nghe.huavan