I am learning bloc and was making a todo app but while calling my bloc listener in addition to do screen it is throwing an error. Error is showing in Add To-Do Class
The exception has occurred. ProviderNotFoundException (Error: Could not find the correct Provider above this BlocListener<TodosBloc, TodosState> 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 BlocListener<TodosBloc, TodosState> 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>().toString()),
);
}
```
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, child) {
// No longer throws
return Text(context.watch<Example>().toString());
}
);
}
```
If none of these solutions work, consider asking for help on StackOverflow:
https://stackoverflow.com/questions/tagged/flutter
)
Here is my code...
Main.dart
import 'package:bloc_practise/blocs/todos/todos_bloc.dart';
import 'package:bloc_practise/todo_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'home_screen.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Color(0xff000A1F),
appBarTheme: AppBarTheme(
color: Color(0xff000A1F),
),
),
home: MultiBlocProvider(providers: [
BlocProvider(
create: (context) => TodosBloc()
..add(
LoadTodo(
todos: [
Todo(
id: '1',
task: 'Sample Todo 1',
description: 'This is a test Todo',
),
Todo(
id: '2',
task: 'Sample Todo 2',
description: 'This is a test Todo',
),
],
),
),
)
], child: HomeScreen()),
);
}
}
HomeScreen.Dart
import 'package:bloc_practise/blocs/todos/todos_bloc.dart';
import 'package:bloc_practise/todo_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'add_todo_screen.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<TodosBloc, TodosState>(
builder: (context, state) {
if (state is TodosLoading) {
return CircularProgressIndicator();
}
if (state is TodosLoaded) {
return Scaffold(
appBar: AppBar(
title: Text('Bloc Pattern To Dos'),
actions: [
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddToDo(),
),
);
},
icon: Icon(
Icons.add,
color: Colors.white,
),
),
],
),
body: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Text(
'Pending To Dos..',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
ListView.builder(
shrinkWrap: true,
itemCount: state.todos.length,
itemBuilder: (context, index) {
return _todoCard(state.todos[index]);
})
]),
),
);
} else {
return Text('Something Went Wrong');
}
},
);
}
}
Card _todoCard(Todo todo) {
return Card(
margin: EdgeInsets.only(bottom: 8.0, top: 8),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'#${todo.id}: ${todo.task}',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Row(
children: [
IconButton(
onPressed: () {},
icon: Icon(
Icons.add_task,
),
),
IconButton(
onPressed: () {},
icon: Icon(
Icons.cancel,
),
),
],
)
],
),
),
);
}
Add To Do Screen.Dart
import 'package:bloc_practise/blocs/todos/todos_bloc.dart';
import 'package:bloc_practise/todo_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class AddToDo extends StatelessWidget {
TextEditingController controllerId = TextEditingController();
TextEditingController controllerTask = TextEditingController();
TextEditingController controllerDescription = TextEditingController();
AddToDo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Add to Dos'),
),
body: BlocListener<TodosBloc, TodosState>(
listener: (context, state) {
if (state is TodosLoaded) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("To Do Added Successfuly"),
),
);
}
},
child: Card(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: [
_inputField('ID', controllerId),
_inputField('Task', controllerTask),
_inputField('Description', controllerDescription),
Builder(builder: (context) {
return ElevatedButton(
onPressed: () {
var todo = Todo(
id: controllerId.text,
task: controllerTask.text,
description: controllerDescription.text,
);
context.read<TodosBloc>().add(AddTodo(todo: todo));
},
child: Text('Add Todo'),
style: ElevatedButton.styleFrom(
primary: Theme.of(context).primaryColor,
),
);
}),
],
),
),
),
),
);
}
}
_inputField(String label, TextEditingController controller) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${label}:',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Container(
height: 50,
margin: EdgeInsets.only(
bottom: 10,
),
width: double.infinity,
child: TextFormField(
controller: controller,
),
)
],
);
}
CodePudding user response:
If you intend to use a bloc on multiple pages, you must put it above the MaterialApp
widget, this is because every page is a child of the MaterialPage
, please take a moment to read your error message:
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.
So instead of having
MaterialApp(
...
home: MultiBlocProvider(
...
),
...
);
do this:
MultiBlocProvider(
...
child: MaterialApp(
...
),
...
);