throw providernotfoundexception(t, context.widget.runtimetype); - flutter

I'm learning flutter and decided to work on a todo list application using cubit. I am created a cubit using bloc provider in the homescreen and in another screen I'm trying to consume the same cubit directly without creating another one.
Homescreen cubit section and creating database using cubit:
I created the cubit here and created the database.
class Homescreen extends StatelessWidget {
const Homescreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => appcubit()..CreateDatabase(),
child: BlocConsumer<appcubit, appStates>(
listener: (context, state) {
// ignore: todo
// TODO: implement listener
},
builder: (context, state) {
appcubit cubit = appcubit.get(context);
return Scaffold(
I have a button that directs to a second page:
Widget buildTaskCat(tasknum, cat, progress, context) {
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => cattaskview(
cat: cat,
progress: progress,
tasknum: tasknum,
),
),
);
},
On the second page Im trying to consume the cubit without using bloc provider. When I use bloc provider somehow I cant access the data in the database and I have to call create database again.
class cattaskview extends StatelessWidget {
const cattaskview(
{Key? key,
required this.cat,
required this.tasknum,
required this.progress})
: super(key: key);
final String cat;
final int tasknum;
final double progress;
#override
Widget build(BuildContext context) {
return BlocConsumer<appcubit, appStates>(
listener: (context, state) {
// TODO: implement listener
},
builder: (context, state) {
return Scaffold(
I get this error message when I try to run
if (inheritedElement == null && null is! T) {
throw ProviderNotFoundException(T, context.widget.runtimeType);
}
return inheritedElement;
}

Have you tried using the BlocProvider.value() Widget?
For example:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: BlocProvider.of<appcubit>(context)
child: cattaskview(),
)
)
);

I fixed the issue by creating the cubit before material app
void main() {
Bloc.observer = MyBlocObserver();
runApp(const Todo());
}
class Todo extends StatelessWidget {
const Todo({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => appcubit()..CreateDatabase(),
child: BlocConsumer<appcubit, appStates>(listener: (context, state) {
// TODO: implement listener
}, builder: (context, state) {
return MaterialApp(
theme: ThemeData(
appBarTheme: const AppBarTheme(
systemOverlayStyle: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.light,
),
),
),
home: Homescreen(),
debugShowCheckedModeBanner: false);
}));
}
}

Related

Could not find the correct Provider above the BlocListener Widget

I'm trying to use Bloc provider for user authentication in my flutter app. When I try to access the data i'm always getting this error even though I double checked all the files.
This is the error i'm getting:
Error: Could not find the correct Provider<StateStreamable<Object?>> above this
BlocListener<StateStreamable<Object?>, Object?> Widget
This happens because you used a `BuildContext` that does not include the provider
main.dart:
void main() async {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => AuthBloc(LoginInitState(), AuthRepository()))
],
child: MaterialApp(
title: 'Flutter app',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity),
home: const LoginPage(),
),
);
}
}
parts from login.dart:
#override
void initState() {
authBloc = BlocProvider.of<AuthBloc>(context);
super.initState();
}
######################################################
return Scaffold(
backgroundColor: Colors.grey[300],
body: BlocListener(
listener: (context, state) {
if (state is UserLoginSuccessState) {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const HomeScreen()));
}
},
child: SafeArea...
I'm still new to flutter and struggling with the state management part, I'd be glad if anybody can help!
In your BlocListener you're missing the State and the Bloc
Here's what I mean
BlocListener<AuthBloc, AuthState>(
listener: (context, state) {
if (state is UserLoginSuccessState) {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const HomeScreen()));
}
},
child: SafeArea...

Could not find the correct Provider above this Test widget

======== Exception caught by gesture ===============================================================
The following ProviderNotFoundException was thrown while handling a gesture:
Error: Could not find the correct Provider above this Test Widget
This happens because you used a BuildContext that does not include the provider
of your choice. There are a few common scenarios:
You added a new provider in your main.dart and performed a hot-reload.
To fix, perform a hot-restart.
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that Test is under your MultiProvider/Provider.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
consider using builder like so:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
If none of these solutions work, consider asking for help on StackOverflow:
https://stackoverflow.com/questions/tagged/flutter
I am building an Widget "Test" to search users by their username. This is the widget Test with Bloc.
class Test extends StatelessWidget {
const Test({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => DonorsCubit(),
child: BlocListener<DonorsCubit, DonorsState>(
listener: (context, state) {
print(state);
},
child: Scaffold(
appBar: AppBar(),
body: IconButton(
onPressed: () {
context.read<DonorsCubit>().searchDonors(searchKey: "masum");
},
icon: BlocBuilder<DonorsCubit, DonorsState>(
builder: (context, state) {
if (state is DonorsInitialState) return const Icon(Icons.add);
if (state is DonorsLoadedState) return const Icon(Icons.done);
if (state is DonorsLoadingState) return const Icon(Icons.circle);
return const SizedBox();
},
),
),
),
),
);
}
}
I used this cubit to manage states.
class DonorsCubit extends Cubit<DonorsState> {
List<MyUser> users = <MyUser>[];
final FirebaseDBRepo _firebaseDBRepo = FirebaseDBRepo();
late StreamSubscription _streamSubscription;
DonorsCubit() : super(DonorsInitialState()) {
_streamSubscription =
_firebaseDBRepo.usersStream().listen((List<MyUser> users) {
this.users = users;
});
}
void searchDonors({required String? searchKey}) {
emit(DonorsLoadingState());
List<MyUser> searchedUser = <MyUser>[];
searchedUser.clear();
if (searchKey == null) {
emit(DonorsLoadedState(users: users));
} else {
for (MyUser user in users) {
if (user.username!.toLowerCase().contains(searchKey.toLowerCase())) {
searchedUser.add(user);
}
}
emit(DonorsLoadedState(users: searchedUser));
}
}
#override
Future<void> close() {
_streamSubscription.cancel();
return super.close();
}
}
abstract class DonorsState extends Equatable {
const DonorsState();
}
class DonorsLoadingState extends DonorsState {
#override
List<Object> get props => [];
}
class DonorsInitialState extends DonorsState {
#override
List<Object> get props => [];
}
class DonorsLoadedState extends DonorsState {
final List<MyUser> users;
const DonorsLoadedState({required this.users});
#override
List<Object?> get props => [users];
}
The problem you get is related to how the provider package works. In order to access the cubit, you should provide it above in the widget tree. Now, you provide and listen to the cubit in the same context. There are several ways how you could handle it.
Use the Builder widget.
class Test extends StatelessWidget {
const Test({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => DonorsCubit(),
child: Builder(
builder: (context) => BlocListener<DonorsCubit, DonorsState>(
listener: (context, state) {
print(state);
},
child: Scaffold(
appBar: AppBar(),
body: IconButton(
onPressed: () {
context.read<DonorsCubit>().searchDonors(searchKey: "masum");
},
icon: BlocBuilder<DonorsCubit, DonorsState>(
builder: (context, state) {
if (state is DonorsInitialState) return const Icon(Icons.add);
if (state is DonorsLoadedState) return const Icon(Icons.done);
if (state is DonorsLoadingState)
return const Icon(Icons.circle);
return const SizedBox();
},
),
),
),
),
),
);
}
}
Split your widget into two and provide your cubit in the parent widget:
class TestWrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => DonorsCubit(),
child: const Test(),
);
}
}
class Test extends StatelessWidget {
const Test({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocListener<DonorsCubit, DonorsState>(
listener: (context, state) {
print(state);
},
child: Scaffold(
appBar: AppBar(),
body: IconButton(
onPressed: () {
context.read<DonorsCubit>().searchDonors(searchKey: "masum");
},
icon: BlocBuilder<DonorsCubit, DonorsState>(
builder: (context, state) {
if (state is DonorsInitialState) return const Icon(Icons.add);
if (state is DonorsLoadedState) return const Icon(Icons.done);
if (state is DonorsLoadingState) return const Icon(Icons.circle);
return const SizedBox();
},
),
),
),
);
}
}
I am a fan of option 2 since it is more clear that you are splitting your code and working in separate contexts.
BONUS
Instead of using BlocListener and BlocBuilder separately, you could use the BlocConsumer widget:
class TestWrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => DonorsCubit(),
child: const Test(),
);
}
}
class Test extends StatelessWidget {
const Test({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: IconButton(
onPressed: () {
context.read<DonorsCubit>().searchDonors(searchKey: "masum");
},
icon: BlocConsumer<DonorsCubit, DonorsState>(
listener: (context, state) {
print(state);
},
builder: (context, state) {
if (state is DonorsInitialState) return const Icon(Icons.add);
if (state is DonorsLoadedState) return const Icon(Icons.done);
if (state is DonorsLoadingState) return const Icon(Icons.circle);
return const SizedBox();
},
),
),
);
}
}
I have the same problem, I use the MultiProvider to list my providers like this:
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Example()),
],
child: MaterialApp(
title: 'Example',
debugShowCheckedModeBanner: false,
theme: ThemeData.dark().copyWith(
textTheme: GoogleFonts.poppinsTextTheme(Theme.of(context).textTheme)
),
// here I set my first screen...
home: HomePage(),
),
);
}

How to call a function in cubit class in initState?

So, I have made a function in Cubit Class it is to get data from API. For now I just can get the data if I pressed a button. I wanna make the function automatically called when the page/screen is open. For your information, this page is the first page that will be launched when user open the app. Here is some of my codes.
class UsersCubit extends Cubit<UsersState> {
UsersCubit() : super(UsersInitial());
UserRepository _userRepository = UserRepository();
void getAllUsers() async{
emit(UsersLoading());
try{
ResponseUsers _data = await _userRepository.getUsers();
emit(UsersSuccess(_data));
} catch(e){
emit(UsersError(e.toString()));
}
}
}
class UsersPage extends StatefulWidget {
const UsersPage({Key? key}) : super(key: key);
#override
_UsersPageState createState() => _UsersPageState();
}
class _UsersPageState extends State<UsersPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Users")),
body: BlocProvider(
create: (context) => UsersCubit(),
child: BlocConsumer<UsersCubit, UsersState>(
listener: (context, state) {
if(state is UsersLoading){
print("getting users ...");
} else if (state is UsersSuccess){
print(state.data.users[1].identity!.name);
} else if (state is UsersError){
print(state.errorMessage);
}
},
builder: (context, state) {
return Stack(
children: [
(state is UsersSuccess) ? listViewUsers(state.data.users) : progressBar(),
ElevatedButton(
onPressed: (){
context.read<UsersCubit>().getAllUsers();
},
child: Text("GET USERS"),
)
],
);
},
),
),
);
}
}
I have tried to call the function directly in initState but when I run the app it returns an error.
#override
void initState() {
context.read<UsersCubit>().getAllUsers();
super.initState();
}
error:
Error: Could not find the correct Provider<UsersCubit> above this UsersPage Widget
This happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:
- You added a new provider in your `main.dart` and performed a hot-reload.
To fix, perform a hot-restart.
- The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
- You used a `BuildContext` that is an ancestor of the provider you are trying to read.
Make sure that UsersPage is under your MultiProvider/Provider<UsersCubit>.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
...
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
...
consider using `builder` like so:
...
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
Is there any way to solve this case?
Can you try wrapp BlocConsumer inside a Builder ?
import 'package:flutter/material.dart';
class UsersPage extends StatefulWidget {
const UsersPage({Key? key}) : super(key: key);
#override
_UsersPageState createState() => _UsersPageState();
}
class _UsersPageState extends State<UsersPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Users")),
body: BlocProvider(
create: (context) {
final cubit = UsersCubit();
cubit.getAllUsers();
return cubit;
},
child: Builder(builder: (context) {
return BlocConsumer<UsersCubit, UsersState>(
listener: (context, state) {
if(state is UsersLoading){
print("getting users ...");
} else if (state is UsersSuccess){
print(state.data.users[1].identity!.name);
} else if (state is UsersError){
print(state.errorMessage);
}
},
builder: (context, state) {
return Stack(
children: [
(state is UsersSuccess) ? listViewUsers(state.data.users) : progressBar(),
ElevatedButton(
onPressed: (){
context.read<UsersCubit>().getAllUsers();
},
child: Text("GET USERS"),
)
],
);
},
);
}),
),
);
}
}
I have solved this case with help from #Ehsan Askari. He suggests me to provide the cubit above the MaterialApp, then I did it. Here is my code now
class AppWidget extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => UsersCubit(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: UsersPage(),
),
);
}
}
class UsersPage extends StatefulWidget {
const UsersPage({Key? key}) : super(key: key);
#override
_UsersPageState createState() => _UsersPageState();
}
class _UsersPageState extends State<UsersPage> {
#override
void initState() {
context.read<UsersCubit>().getAllUsers();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Users")),
body: BlocConsumer<UsersCubit, UsersState>(
listener: (context, state) {
if(state is UsersLoading){
print("getting users ...");
} else if (state is UsersSuccess){
print(state.data.users[1].identity!.name);
} else if (state is UsersError){
print(state.errorMessage);
}
},
builder: (context, state) {
return (state is UsersSuccess) ? listViewUsers(state.data.users) : progressBar();
},
),
);
}
}
you can call it from your Blocprovider by accessing your class like this :-
BlocProvider(
create: (context) => Usercubit()..getAllUsers(),
build : (context) => Scaffold() ........
You don't need to call a function inside initState when using Bloc or cubit, just call it when creating the Cubit inside BlocProvider like this >>.
class UsersPage extends StatefulWidget {
const UsersPage({Key? key}) : super(key: key);
#override
_UsersPageState createState() => _UsersPageState();
}
class _UsersPageState extends State<UsersPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Users")),
body: BlocProvider(
/// after create the cubit you can call the method.
create: (context) => UsersCubit()..getAllUsers();,
child: BlocConsumer<UsersCubit, UsersState>(
listener: (context, state) {
if(state is UsersLoading){
print("getting users ...");
} else if (state is UsersSuccess){
print(state.data.users[1].identity!.name);
} else if (state is UsersError){
print(state.errorMessage);
}
},
builder: (context, state) {
return Stack(
children: [
(state is UsersSuccess) ? listViewUsers(state.data.users) : progressBar(),
ElevatedButton(
onPressed: (){
context.read<UsersCubit>().getAllUsers();
},
child: Text("GET USERS"),
)
],
);
},
),
),
);
}
}

Passing Arguments between pages but show this error

I m trying to pass arguments between pages but I m getting this error:
FlutterError (Could not find a generator for route RouteSettings("detail", Instance of 'Commodity') in the _WidgetsAppState.
Make sure your root app widget has provided a way to generate
this route.
Generators for routes are searched for in the following order:
For the "/" route, the "home" property, if non-null, is used.
Otherwise, the "routes" table is used, if it has an entry for the route.
Otherwise, onGenerateRoute is called. It should return a non-null value for any valid route not handled by "home" and "routes".
Finally if all else fails onUnknownRoute is called.
Unfortunately, onUnknownRoute was not set.)
I don't know why because 'detail' page already setted
This is my Main App
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: WelcomePage.routeName,
routes: {
'/welcome': (_) => const WelcomePage(),
'detail': (_) => SubCommoditiePage(),
},
);
}
}
This is my From Page
class DisplayOptions extends StatelessWidget {
final List<Commodity> _optionsToDisplay;
const DisplayOptions(this._optionsToDisplay);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _optionsToDisplay.length,
itemBuilder: (context, index) {
final opt = _optionsToDisplay[index];
return ListTile(
title: Text(opt.label),
subtitle: Text(opt.shortLabel),
onTap: () {
Navigator.pushNamed(context, 'detail', arguments: _optionsToDisplay[index]);
});
});
}
}
This is my Destination Page
class SubCommoditiePage extends StatefulWidget {
const SubCommoditiePage({Key? key}) : super(key: key);
static const String routenName = 'detail';
static Route route() {
return MaterialPageRoute(
builder: (_) => const SubCommoditiePage(),
settings: const RouteSettings(name: routenName));
}
#override
_SubCommoditiePageState createState() => _SubCommoditiePageState();
}
class _SubCommoditiePageState extends State<SubCommoditiePage> {
#override
Widget build(BuildContext context) {
final Commodity commoditySeleted =
ModalRoute.of(context)?.settings.arguments as Commodity;
return Scaffold(
appBar: AppBar(
title: Text(commoditySeleted.label),
),
);
}
}
For initial/homepage, use /. In this case your WelcomePage.routeName will be /;
and route
routes: {
WelcomePage.routeName: (_) => WelcomePage(),
..........
},
You don't need to pass initialRoute while the root '/' will be selected.
For more about named-routes
The way I was able to solve it was:
I evidently didn't know why flutter didn't recognize my 'detail' page.
And I had to do it this way:
This is my From Page
in my ontap, I used
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SubCommoditiePage(
seleted: _optionsToDisplay[index],
)));
like that:
class DisplayOptions extends StatelessWidget {
final List<Commodity> _optionsToDisplay;
const DisplayOptions(this._optionsToDisplay);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _optionsToDisplay.length,
itemBuilder: (context, index) {
final opt = _optionsToDisplay[index];
return ListTile(
title: Text(opt.label),
subtitle: Text(opt.shortLabel),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SubCommoditiePage(
seleted: _optionsToDisplay[index],
)));
});
});
}
}
adding to my page: final Commodity seleted; and with widget.selected... I was able to use it perfectly!
class SubCommoditiePage extends StatefulWidget {
final Commodity seleted;
const SubCommoditiePage({required this.seleted, Key? key}) : super(key: key);
static const String routenName = 'detail';
#override
_SubCommoditiePageState createState() => _SubCommoditiePageState();
}
class _SubCommoditiePageState extends State<SubCommoditiePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.seleted.label),
backgroundColor: const Color.fromRGBO(37, 59, 128, 5),
),
body: ListView.builder(
itemCount: widget.seleted.subCommodities.length,
itemBuilder: (context, index) {
final opt = widget.seleted.subCommodities[index];
return ListTile(
title: Text(opt.label),
onTap: () {},
);
}));
}
}

Why is the BlocBuilder never called when bloc is not set explicitly

This is an example of a Flutter counter app. I instantiate the Counter with a Bloc like this:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Counter(CounterBloc()),
);
}
}
This code below works fine. Event is dispatched and the "builder" method is called.
class Counter extends StatelessWidget {
final Bloc bloc;
const Counter(this.bloc, {Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider<CounterBloc>(
create: (context) => bloc,
child: CounterPage(),
);
}
}
class CounterPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: BlocBuilder<CounterBloc, int>(
builder: (context, count) => CountView(count),
),
floatingActionButton: AddButton(
action: () => BlocProvider.of<CounterBloc>(context)
.add(CounterEvent.increment)),
);
}
}
The code below does not work. The event is dispatched but the builder is never called.
class Counter extends StatelessWidget {
final Bloc bloc;
const Counter(this.bloc, {Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider<CounterBloc>(
create: (context) => bloc,
child: Scaffold(
body: BlocBuilder<CounterBloc, int>(
builder: (context, count) => CountView(count),
),
floatingActionButton: AddButton(
action: () => BlocProvider.of<CounterBloc>(context)
.add(CounterEvent.increment)),
),
);
}
}
I found out that I can set property "bloc" on a "BlocBuilder" but I'd expect it's not necessary.
Why the difference in behavior?
I believe the CounterEvent.increment from not working snippet won't get dispatched and instead will throw an error BlocProvider.of() called with a context ... because you use the same context where you provided the bloc.
This code works because it's a new context after BlocProvider
class Counter extends StatelessWidget {
final Bloc bloc;
const Counter(this.bloc, {Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider<CounterBloc>(
create: (context) => bloc,
child: Builder(
builder: (context) => Scaffold(
body: BlocBuilder<CounterBloc, int>(
builder: (context, count) => CountView(count),
),
floatingActionButton: AddButton(
action: () => BlocProvider.of<CounterBloc>(context)
.add(CounterEvent.increment),
),
),
),
);
}
}
This code also works because we explicitly use the bloc instance from the constructor instead of calling BlocProvider.of() and using the bloc instance provided via BlocProvider.
class Counter extends StatelessWidget {
final Bloc bloc;
const Counter(this.bloc, {Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider<CounterBloc>(
create: (context) => bloc,
child: Scaffold(
body: BlocBuilder<CounterBloc, int>(
bloc: bloc,
builder: (context, count) => CountView(count),
),
floatingActionButton: AddButton(
action: () => bloc.add(CounterEvent.increment),
),
),
);
}
}
Both snippets above will work but it's not exactly the "correct" way.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Counter(
CounterBloc(), // <=() You need a work around to dispose this instance
),
);
}
}