Flutter - Provider Package
Last Updated :
25 Apr, 2025
The provider package is an easy to use package which is basically a wrapper around the InheritedWidgets that makes it easier to use and manage. It provides a state management technique that is used for managing a piece of data around the app.
The basic classes available in the provider package are -
- ChangeNotifierProvider<T extends ChangeNotifier>: It listens to a ChangeNotifier extended by the model class, exposes it to its children and descendants, and rebuilds its dependencies whenever notifyListeners is called.
ChangeNotifierProvider(
create: (context) => DataModel(),
child: ...
)
- Consumer<T>: It obtains the provider from its ancestors and passes the value obtained to the builder.
@override
Widget build(BuildContext context) {
return Consumer<DataModel>(
builder:
(context, data, child) => Column(children: [child!, Text(data.first)]),
child: Text('Static widget'), // This stays constant
);
}
- FutureProvider<T>: This class listens for a Future and then passes its values to its children and descendants.
Constructors
FutureProvider<T>(
{Key key,
@required Create<Future<T>> create,
T initialData,
ErrorBuilder<T> catchError,
UpdateShouldNotify<T> updateShouldNotify,
bool lazy,
TransitionBuilder builder,
Widget child}
)
This creates a Future from create and subscribes to it.
FutureProvider.value(
{Key key,
@required Future<T> value,
T initialData,
ErrorBuilder<T> catchError,
UpdateShouldNotify<T> updateShouldNotify,
TransitionBuilder builder,
Widget child}
)
This constructor notifies the changed values to the FutureProvider children.
Ex: FutureProvider<Model>(create: (context) =>
Model(),)
- InheritedProvider<T> The InheritedProvider provides a general implementation of the InheritedWidget.
- MultiProvider A provider that is used to provide more than one class at the same time.
MultiProvider(
providers: [
Provider<Model1>(create: (context) => Model1()),
StreamProvider<Model2>(create: (context) => Model2()),
FutureProvider<Model3>(create: (context) => Model3()),
],
child: someWidget,
)
- Provider<T> It is the basic provider.
- ProxyProvider<T, R> This provider depends on other providers for value. The value can be used by create or update.
Constructor
ProxyProvider(
{Key key,
Create<R> create,
@required ProxyProviderBuilder<T, R> update,
UpdateShouldNotify<R> updateShouldNotify,
Dispose<R> dispose, bool lazy,
TransitionBuilder builder,
Widget child}
)
This initializes key for subclasses.
- StreamProvider<T> This class listens for a Stream and then passes its values to its children and descendants. This can be used as
Constructors
StreamProvider<T>(
{Key key,
@required Create<Stream<T>> create,
T initialData,
ErrorBuilder<T> catchError,
UpdateShouldNotify<T> updateShouldNotify,
bool lazy,
TransitionBuilder builder,
Widget child}
)
This creates a stream using create and subscribes to it.
StreamProvider.value(
{Key key,
@required Stream<T> value,
T initialData,
ErrorBuilder<T> catchError,
UpdateShouldNotify<T> updateShouldNotify,
bool lazy,
TransitionBuilder builder,
Widget child}
)
This constructor notifies the changed values to the StreamProvider children.
Ex: StreamProvider<Model>(create: (context) =>
Model(),)
- ValueListenableProvider<T> This class receives changes in value by subscribing to a ValueListenable.
ValueListenableProvider<T>.value(
{Key key,
@required ValueListenable<T> value,
UpdateShouldNotify<T> updateShouldNotify,
TransitionBuilder builder,
Widget child}
)
This constructor shows the changed values to its children.
Apart from these, there are a number of other classes that are available depending upon the need but these are the most used. Let's understand the concept with an example.
Step-by-Step Implementation
Step 1: Create a new Flutter Application
Create a new Flutter application using the command Prompt. To create a new app, write the following command and run it.
flutter create app_name
To know more about it refer this article: Creating a Simple Application in Flutter
Step 2: Adding the Dependency
To add the dependency to the pubspec.yaml file, add provider as a dependency in the dependencies part of the pubspec.yaml file, as shown below:
Dart
dependencies:
flutter:
sdk: flutter
provider: ^6.1.4
Now, run the command below in the terminal.
flutter pub get
Or
Run the command below in the terminal.
flutter pub add provider
Step 3: Import dependencies
To use libraries, import all of them in the respective .dart file,
import 'package:provider/provider.dart';
Step 4: Folder Structure
Follow the file structure below for better understanding.
Step 5: Start Coding
First of all, we will be defining a model library inside of the lib folder which consists of item.dart and item_data.dart. Apart from these, the lib will have 3 more dart files namely the main.dart, home.dart, and item_list.dart.
The item.dart is a simple class that defines what are the attributes that the item class will hold and a toggle method.
- item.dart:
Dart
import 'package:flutter/foundation.dart';
class Item {
String item;
bool completed;
Item({@required this.item, this.completed = false});
void toggle() {
completed = !completed;
}
}
The item_data.dart contains a list that will hold the data of the Item class defined above. There are methods to perform tasks such as add, toggle, and remove an item from the list.
- item_data.dart:
Dart
import 'dart:collection';
import 'package:flutter/foundation.dart';
import '../model/item.dart';
class ItemData with ChangeNotifier {
List<Item> _items = [];
UnmodifiableListView<Item> get items => UnmodifiableListView(_items);
get size => _items.length;
void addItem(Item item) {
_items.add(item);
notifyListeners();
}
void toggleItem(Item item) {
item.toggle();
notifyListeners();
}
void removeItem(Item item) {
_items.remove(item);
notifyListeners();
}
}
The item_list.dart creates a ListView builder of the data coming from the list. It uses the Consumer to get the data.
- item_list.dart:
Dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'model/item_data.dart';
class ItemList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<ItemData>(builder: (context, data, child) {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: data.size,
itemBuilder: (context, index) {
final item = data.items[index];
return GestureDetector(
onLongPress: () => data.removeItem(item),
child: Container(
padding: EdgeInsets.symmetric(vertical: 5),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blueGrey,
child: Text(item.item[0]),
),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
item.item,
style: TextStyle(
decoration: item.completed
? TextDecoration.lineThrough
: null,
fontSize: 16,
fontWeight: FontWeight.bold),
),
Checkbox(
value: item.completed,
onChanged: (c) => data.toggleItem(item),
),
],
),
),
),
);
},
);
});
}
}
Step 7: Develop UI
- showDialog: Used to show an AlertDialog for adding a list member.
Dart
showDialog(
context: context,
builder: (context) {
String item = '';
return AlertDialog(
title: const Text('Add Item'),
content: TextField(
onChanged: (value) {
item = value;
},
decoration: const InputDecoration(hintText: 'Enter item name'),
),
actions: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
onPressed: () {
if (item.isNotEmpty) {
Provider.of<ItemData>(context, listen: false).addItem(Item(item: item));
Navigator.pop(context);
}
},
child: const Text('Add'),
),
],
);
},
);
-main.dart:
Dart
import 'package:flutter/material.dart';
import 'package:flutter_geeks/item.dart';
import 'package:flutter_geeks/item_list.dart';
import 'package:provider/provider.dart';
import './item_data.dart';
// Entry point of the Flutter application
void main() {
runApp(MyApp());
}
// Main application widget
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
// Providing the ItemData model to the widget tree
create: (context) => ItemData(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Provider Demo',
home: Home(), // Sets the Home widget as the initial screen
),
);
}
}
// Home widget, which is a stateful widget
class Home extends StatefulWidget {
const Home({super.key});
@override
State<Home> createState() => _HomeState();
}
// State class for the Home widget
class _HomeState extends State<Home> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Provider Demo'),
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
body: ItemList(), // Displays the list of items
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
onPressed: () {
// Opens a dialog to add a new item
showDialog(
context: context,
builder: (context) {
String item = ''; // Variable to store the entered item name
return AlertDialog(
title: const Text('Add Item'),
content: TextField(
onChanged: (value) {
item = value; // Updates the item name as the user types
},
decoration: const InputDecoration(hintText: 'Enter item name'), // Hint text for the input field
),
actions: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
onPressed: () {
if (item.isNotEmpty) {
// Adds the item to the list if the input is not empty
Provider.of<ItemData>(context, listen: false).addItem(Item(item: item));
Navigator.pop(context); // Closes the dialog
}
},
child: const Text('Add'),
),
],
);
},
);
},
child: const Icon(Icons.add), // Icon for the floating action button
),
);
}
}
The main.dart has a ChangeNotifierProvider which acts as a parent to the material app. As our app is quite small we have defined the provider at the top only. In case your app is quite large you can place the provider at the top of the widget that needs the data and not at the top.
Complete Source Code:
item.dart
class Item {
String item;
bool completed;
Item({required this.item, this.completed = false});
void toggle() {
completed = !completed;
}
}
item_data.dart
import 'dart:collection';
import 'package:flutter/foundation.dart';
import './item.dart';
class ItemData with ChangeNotifier {
List<Item> _items = [];
UnmodifiableListView<Item> get items => UnmodifiableListView(_items);
get size => _items.length;
void addItem(Item item) {
_items.add(item);
notifyListeners();
}
void toggleItem(Item item) {
item.toggle();
notifyListeners();
}
void removeItem(Item item) {
_items.remove(item);
notifyListeners();
}
}
item_list.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import './item_data.dart';
class ItemList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<ItemData>(
builder: (context, data, child) {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: data.size,
itemBuilder: (context, index) {
final item = data.items[index];
return GestureDetector(
onLongPress: () => data.removeItem(item),
child: Container(
padding: EdgeInsets.symmetric(vertical: 5),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
child: Text(item.item[0]),
),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
item.item,
style: TextStyle(
decoration:
item.completed
? TextDecoration.lineThrough
: null,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Checkbox(
value: item.completed,
onChanged: (c) => data.toggleItem(item),
),
],
),
),
),
);
},
);
},
);
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_geeks/item.dart';
import 'package:flutter_geeks/item_list.dart';
import 'package:provider/provider.dart';
import './item_data.dart';
// Entry point of the Flutter application
void main() {
runApp(MyApp());
}
// Main application widget
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
// Providing the ItemData model to the widget tree
create: (context) => ItemData(),
child: MaterialApp(
debugShowCheckedModeBanner: false, // Disables the debug banner
title: 'Provider Demo',
theme: ThemeData(
primarySwatch: Colors.green, // Sets the primary theme color
),
home: Home(), // Sets the Home widget as the initial screen
),
);
}
}
// Home widget, which is a stateful widget
class Home extends StatefulWidget {
const Home({super.key});
@override
State<Home> createState() => _HomeState();
}
// State class for the Home widget
class _HomeState extends State<Home> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Provider Demo'),
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
body: ItemList(), // Displays the list of items
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
onPressed: () {
// Opens a dialog to add a new item
showDialog(
context: context,
builder: (context) {
String item = ''; // Variable to store the entered item name
return AlertDialog(
title: const Text('Add Item'),
content: TextField(
onChanged: (value) {
item = value; // Updates the item name as the user types
},
decoration: const InputDecoration(hintText: 'Enter item name'), // Hint text for the input field
),
actions: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
onPressed: () {
if (item.isNotEmpty) {
// Adds the item to the list if the input is not empty
Provider.of<ItemData>(context, listen: false).addItem(Item(item: item));
Navigator.pop(context); // Closes the dialog
}
},
child: const Text('Add'),
),
],
);
},
);
},
child: const Icon(Icons.add), // Icon for the floating action button
),
);
}
}
Output:
Apart from Provider, there are other State Management tools also available such as -
- StatefulWidget: These are the widgets provided in the material package. These widgets have an internal state which can be re-built if the input changes or if the widget’s state changes.
- InheritedWidget: These are simple widgets that hold the data that is to be used by their children or descendants. These provide a simple mechanism to move data to a child much below in the widget tree. There is an element associated with it that changes the data when the element updates. The provider package is a wrapper around the InheritedWidgets.
- ScopedModel: This library is taken from the Fuchsia codebase which provides a method to pass the data from Parents to their children. When the model changes the children are rebuilt. Our class can extend the Model class to create our Models. ScopedModel Widget is wrapped around the widget whose data needs to be sent down the widget tree. ScopedModelDescendant Widget is used to listen to changes that happen to the Model and rebuild the child.
- BLoC: Business Logic Component. This technique allows us to handle data as a Stream of events. It comes between the UI and the data that handles the logic for the application. The main components of BLoC are Sink and Stream. The StreamController handles these components. The sink is used to add data/events and the Stream is used to listen to them.
Similar Reads
Flutter - State Management Provider
In this article, we are going to learn how state management is achieved in Flutter using providers. But before that, we need to know what a state is. As we know that everything in Flutter is a widget, and there are mainly two kinds of widgets: Stateless Widgets and Stateful Widgets. Stateless widget
8 min read
Placeholder Flutter
Placeholder is a popular, inbuilt widget of the Flutter framework which creates an empty canvas/container on the screen to put content into, just like its name implies. It is analogous to both the placeholder attribute and the <div> tag of HTML. Almost all Flutter developers have reported usin
3 min read
Flutter- Screenshot Package
Flutter is a popular framework by Google which is growing fast with its growing community. The Flutter has created a buzz through its libraries, making the development fast-paced. Nowadays, everyone loves to take screenshots. If your application involves the use of screenshots, Flutter got a package
8 min read
Flutter - Stack Widget
The Stack widget in Flutter is a powerful tool that allows for the layering of multiple widgets on top of each other. While layouts like Row and Column arrange widgets horizontally and vertically, respectively, Stack provides a solution when you need to overlay widgets. For instance, if you want to
6 min read
Flutter - OctoImage Widget
The OctoImage widget in Flutter requires an ImageProvider to display images in an application. The images in the OctoImage widget can be supplied with a Progress indicator or a Place holder for loading the Image in it. An OctoImage widget makes use of the Octosets which are nothing but the combinati
4 min read
Flutter - Radial Gauge
A radial gauge is a graphical representation of a measurement that displays values on a circular scale. It is a type of gauge that is often used to visualize data such as speed, temperature, or progress in a circular format. Radial gauges are commonly used in dashboards, control panels, and other ap
5 min read
Flutter - Material Package
Material Package contains the application icon and a lot of designing tool methods. In this package we don't need to write the whole code for the particular function or method, we just import this package and use it single line. How to Install The Material Package For installing the packages we have
2 min read
Flutter - GridPaper Widget
A grid paper is a paper that has a grid on it with divisions and subdivisions, for example, graph paper. We may use grid paper in creating the graphs in our flutter application. A sample image is given below to get an idea about what we are going to do in this article. Â How to use it?Dart GridPaper(
3 min read
Flutter vs Java
Here, we are going to discuss the two most popular technologies for making apps i.e. Flutter and Java. Imagine it like a showdown between two champs: Flutter and Java. No matter if you're new to coding or a pro, we'll check out what makes these languages tick. So without wasting any time let's explo
7 min read
Flutter - Verified Tick
In many Android applications, we need to make the user account verified. Showing the verified icon in the flutter application is pretty simple. We can use the visibility widget to show and hide the icon. A sample video is given below to get an idea about what we are going to do in this article. How
3 min read