Introduction to Provider
- Getting started
- Provider Overview
-
ChangeNotifier is extended by a class to provide change notifications to its listeners
-
ChangeNotifierProvider listens for changes to a ChangeNotifier. Widgets below it can access the state object and listen to state changes.
-
Consumer wraps around part of a widget tree. It rebuilds part of a subtree when the state it listens to changes.
-
Provider.of allows descendant widgets to access the state object. If you only need access to the state object and don’t need to listen for changes, use this!
- Example : My Notes App
- Creating Note Model
- Crearting NoteManager
- Providing NoteManager
- Notes Screen
- New Note Screen
- Note Screen
Provider : Wraps around inherited widgets. This package allows you to provide data and state information to descendant widgets.
This approach is better. It allows descendant widgets in the subtree to access state
information.
Instead of callbacks, you just wrap Consumers around your widgets.
Every time a
state changes, those Consumers rebuild the subtree below it.
Provider is a convenient way to pass state down the widget tree and rebuild your UI
when changes occur. You’ll add it to your project next.
Before you do that, however, you need to understand four concepts:
Adding Provider : Provider Installing
In the models directory, create a new file called note.dart and add the following code:
class Note {
String title;
String description;
Note(this.title, this.description);
}
In the providers directory, create a new file called notes_manager.dart and add the following code:
import '../models/note.dart';
import 'package:flutter/foundation.dart';
class NotesManager extends ChangeNotifier {
//This manager holds a private array of _noteItems.
// Only the manager can change and update note items.
final List<Note> _noteItems = [];
//Provides a public getter method for _noteItems, which is unmodifiable.
//External entities can only read the list of note items
List<Note> get noteItems => List.unmodifiable(_noteItems);
//Get the note at index in the list
Note geNoteByIndex(int index) {
return _noteItems[index];
}
//addNote() adds a new note item at the end of the list.
void addNote(Note note) {
_noteItems.add(note);
notifyListeners();
}
//deleteNoe() deletes a note at a particular index.
void deleteNote(int index) {
_noteItems.removeAt(index);
notifyListeners();
}
}
It’s time to provide this to other widgets.
Open main.dart and add the following imports.
Then, assign MultiProvider to the runApp. This accepts a list of providers
for the entire app.
ChangeNotifierProvider creates an instance of NoteManager, which listens to
_noteItems and notifies its listeners.
import 'package:flutter/material.dart';
import 'package:my_notes/screens/new_note_screen.dart';
import 'package:my_notes/screens/note_screen.dart';
import 'package:my_notes/screens/notes_screen.dart';
import 'package:provider/provider.dart';
import 'providers/notes_manager.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => NotesManager()),
],
child: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Notes',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: {
"/notes": (context) => NotesScreen(),
"/note": (context) => NoteScreen(),
"/new-note": (context) => NewNoteScreen()
},
home: NotesScreen());
}
}
import 'package:flutter/material.dart';
import 'package:my_notes/providers/notes_manager.dart';
import 'package:provider/provider.dart';
class NotesScreen extends StatelessWidget {
const NotesScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final notesManager = Provider.of<NotesManager>(context);
final notes = notesManager.noteItems;
return Scaffold(
appBar: AppBar(
title: Text("Notes (${notes.length})"),
),
floatingActionButton: FloatingActionButton(
child:const Icon(Icons.add),
onPressed: () {
Navigator.of(context).pushNamed("/new-note");
},
),
body: ListView.builder(
itemCount: notes.length,
itemBuilder: (ctx, index) {
return ListTile(
leading: Text((index + 1).toString()),
title: Text(notes[index].title),
trailing:const Icon(Icons.remove_red_eye_outlined),
onTap: () {
Navigator.of(context).pushNamed("/note", arguments: index);
},
);
},
),
);
}
}
import 'package:flutter/material.dart';
import 'package:my_notes/models/note.dart';
import '../providers/notes_manager.dart';
import 'package:provider/provider.dart';
class NewNoteScreen extends StatelessWidget {
NewNoteScreen({Key? key}) : super(key: key);
final _formKey = GlobalKey<FormState>();
final TextEditingController _titleController = TextEditingController();
final TextEditingController _descriptionController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("New Note"),
),
body: Padding(
padding: const EdgeInsets.all(10),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: const InputDecoration(hintText: "Title"),
validator: (value) {
if (value == null || value.isEmpty) {
return "Please enter a title";
}
return null;
},
controller: _titleController,
),
TextFormField(
decoration: const InputDecoration(hintText: "Description"),
validator: (value) {
if (value == null || value.isEmpty) {
return "Please enter a description";
}
return null;
},
controller: _descriptionController,
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
Note newNote = Note(
_titleController.text, _descriptionController.text);
final notesManager =
Provider.of<NotesManager>(context, listen: false);
notesManager.addNote(newNote);
Navigator.of(context).pop();
}
},
child: const Text("Add"))
],
),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:my_notes/providers/notes_manager.dart';
import 'package:provider/provider.dart';
class NoteScreen extends StatelessWidget {
NoteScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final noteIndex = ModalRoute.of(context)!.settings.arguments as int;
final noteProvider = Provider.of<NotesManager>(context, listen: false);
final note = noteProvider.geNoteByIndex(noteIndex);
return Scaffold(
appBar: AppBar(
title: const Text("Note"),
),
body: ListTile(
title: Text(note.title),
subtitle: Text(note.description),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.delete),
backgroundColor: Colors.red,
onPressed: () {
noteProvider.deleteNote(noteIndex);
Navigator.of(context).pop();
},
),
);
}
}