Bloc Provider
Presentation (Integration)
Summary
This lesson focuses on integrating the presentation layer with state management by providing Cubits to the widget tree. The instructor corrects a previous dependency mistake by switching from the core bloc package to flutter_bloc. The core of the lesson is a deep dive into the lifecycle and scoping of BlocProvider, explaining why placing all providers globally above MaterialApp is an anti-pattern that leads to resource leaks.
Key Ideas
- The flutter_bloc package must be used in Flutter applications, not the pure Dart bloc package.
- MultiBlocProvider is used to provide multiple Blocs or Cubits to the widget tree simultaneously.
- BlocProvider automatically handles the lifecycle of the Bloc/Cubit, calling its close method when the provider is removed from the widget tree.
- Providing a Cubit above MaterialApp keeps it alive for the entire lifespan of the application because the root widget is never unmounted.
- Global providers should be reserved for globally needed states (e.g., authentication, localization, theming).
- To avoid resource leaks, BlocProvider should be scoped as tightly as possible, ideally wrapping only the specific screen or view that requires the state.
Code Snippets
dependencies:
flutter:
sdk: flutter
# bloc: ^8.1.1 (removed)
flutter_bloc: ^8.1.2@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(create: (context) {
return FeaturedBooksCubit(FeaturedBooksUseCase);
}),
],
child: MaterialApp.router(
routerConfig: AppRouter.router,
debugShowCheckedModeBanner: false,
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: kPrimaryColor,
textTheme: GoogleFonts.montserratTextTheme(ThemeData.dark().textTheme),
),
),
);
}Architecture Insight
BlocProvider is where the lifetime of a Cubit is decided. Mount it at the route — usually the screen widget — and the Cubit lives as long as the screen is on the stack. Mount it higher (above MaterialApp) and it's app-scoped.
Wrong scope is a common bug: an app-scoped Cubit holds stale state across screens, and a screen-scoped Cubit dies the moment you navigate away. Match the scope to the data's natural lifetime.
Looking ahead — get-it takes over Cubit *construction* (so widgets don't "new" a Cubit with all its dependencies inline); BlocProvider keeps its role as the thing that scopes the *lifetime*.
My Notes
The instructor gives an excellent explanation of Bloc scoping and widget lifecycle. It's crucial to understand that BlocProvider is responsible for disposing of the instances it creates. By hoisting all providers to the MaterialApp level, you bypass this automatic garbage collection, keeping instances in memory forever. [Editor's note] At 01:27, the code inside create: (context) returns FeaturedBooksCubit(FeaturedBooksUseCase);. FeaturedBooksUseCase is a class type, not an instance. Clean Architecture implementations typically rely on a dependency injection tool like GetIt to provide these use cases, so the correct implementation should eventually look like FeaturedBooksCubit(getIt.get<FeaturedBooksUseCase>()). The video ends before this compilation error is corrected.