Search code examples
flutterdartblocflutter-bloc

Unable to factor out list of `providers` from `MultiBlocProvider`


I want to combine BlocProviders from multiple sources into a single MultiBlocProvider. But any attempt to construct a List of BlocProviders outside of the MultiBlocProvider constructor arguments leads to a runtime error, that the Provider<XYZ> could not be found.

Error: Could not find the correct Provider<Foo> above this BlocListener<Foo, FooState> Widget

Say I have

return MultiBlocProvider(
  providers: [
    BlocProvider(create: (context) => FooCubit()),
    BlocProvider(create: (context) => BarCubit()),
  ],
  child: child,
);

That works. But I want

final concatenatedProviders = [
  BlocProvider(create: (context) => FooCubit()),
] + [
  BlocProvider(create: (context) => BarCubit()),
];
return MultiBlocProvider(
  providers: concatenatedProviders,
  child: child,
);

That does not work. Factoring out the providers does not work even if it is a single (non-concatenated) list.

How can I factor out the providers this so that they will still be found? I have tried several type annotations for the providers, such as List<BlocProvider<StateStreamableSource<Object?>>>, List<BlocProvider<dynamic>>, etc, but I couldn't find a working solution.


Solution

  • Try this,

    final providers = <BlocProvider>[
          BlocProvider<FooCubit>(create: (_) => FooCubit()),
        ] +
        <BlocProvider>[
          BlocProvider<BarCubit>(create: (_) => BarCubit()),
        ];
    

    Full working example:

    //foo_cubit.dart
    
    import 'package:flutter_bloc/flutter_bloc.dart';
    
    class FooCubit extends Cubit<int> {
      FooCubit() : super(0);
    
      void add(int x) {
        emit(state + x);
      }
    
      void substract(int x) {
        emit(state - x);
      }
    
      void multiply(int x) {
        emit(state * x);
      }
    
      void divide(int x) {
        emit(state ~/ x);
      }
    }
    
    
    //bar_cubit.dart
    import 'package:flutter_bloc/flutter_bloc.dart';
    
    class BarCubit extends Cubit<String> {
      BarCubit() : super("");
    
      void append(String str) {
        emit(state + str);
      }
    
      void reverse() {
        emit(String.fromCharCodes(state.codeUnits.reversed));
      }
    
      void clear() {
        emit('');
      }
    }
    
     //main.dart
    import 'package:flutter/material.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    import 'package:temp_bloc_runtime/bar_cubit.dart';
    import 'package:temp_bloc_runtime/foo_cubit.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        final providers = <BlocProvider>[
              BlocProvider<FooCubit>(create: (_) => FooCubit()),
            ] +
            <BlocProvider>[
              BlocProvider<BarCubit>(create: (_) => BarCubit()),
            ];
    
        return MultiBlocProvider(
          providers: providers,
          child: MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: const MyHomePage(title: 'Flutter Demo Home Page'),
          ),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({Key? key, required this.title}) : super(key: key);
    
      final String title;
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                BlocBuilder<FooCubit, int>(
                  builder: (_, state) => Text(
                    state.toString(),
                  ),
                ),
                BlocBuilder<BarCubit, String>(
                  builder: (_, state) => Text(
                    state,
                  ),
                ),
                const Expanded(child: SizedBox.shrink()),
                Row(
                  children: [
                    MaterialButton(
                      onPressed: () => context.read<FooCubit>().add(1),
                      child: const Text('+'),
                    ),
                    MaterialButton(
                      onPressed: () => context.read<FooCubit>().substract(1),
                      child: const Text('-'),
                    ),
                    MaterialButton(
                      onPressed: () => context.read<BarCubit>().append('A'),
                      child: const Text('+A'),
                    )
                  ],
                )
              ],
            ),
          ),
        );
      }
    }