This is a clean, simple example of how to use the Provider API in your flutter app to do state management. The basic functionality is akin to redux, if you are from a React background.
The key aspects of using this are as follows:
- KeepYour provider is a Dart class which has all the shared state as required by your application. For example, if you are implementing a shopping application, this class may hols a list of inventory items as well as the the cart data (items ordered, total value, etc.).
- This class should also implement all the business logic, as required by the application. For instance, it should add up all the total cost of items on order.
- This class should extend ChangeNotifier (in package flutter/material.dart). This ChangeNotifier is responsible for "broadcasting" a notification to all widgets who are listening to changes in the state.
- Our provider class must call "notifyListeners" each time the state changes. For example, if an item is added to the shopping cart, we should re-calculate the totals and call notifyListeners in the ChangeNotifier class.
class CounterProvider extends ChangeNotifier
{
int mCounter = 0;
int getCurrentCount() => mCounter;
void incrementCounter(){
++mCounter; // Since the state has changed, we must notify
notifyListeners();
}
void resetCount(){
mCounter = 0;
notifyListeners();
}
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
// NB: We wrap the UI hirearchy in a ChangeNotificationProvider class
return ChangeNotifierProvider(
create: (context) => CounterProvider(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
),
);
}
}
CounterProvider p;
@override
Widget build(BuildContext context) {
p = Provider.of<counterprovider>(context, listen:true );
Here is the complete code.
import 'package:flutter/material.dart';
import 'package:my_app/counter_provider.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => CounterProvider(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
),
);
}
}
// ------------------------------------------------------------
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late CounterProvider p;
void _increment(){
p.incrementCounter();
}
@override
Widget build(BuildContext context) {
p = Provider.of<CounterProvider>(context, listen:true );
int aCount = p.getCurrentCount();
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$aCount',
style: Theme.of(context).textTheme.headline4,
),
ElevatedButton(onPressed: () => p.resetCount(), child: const Text("Reset counter"),)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _increment,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
And the provider class
import 'package:flutter/material.dart';
class CounterProvider extends ChangeNotifier
{
int mCounter = 0;
int getCurrentCount() => mCounter;
void incrementCounter(){
++mCounter;
notifyListeners();
}
void resetCount(){
mCounter = 0;
notifyListeners();
}
}