Skip to main content

Provider State Management Framework

Introduction to Provider Dart Framework

Provider is a Flutter state management framework for Dart applications. It is a popular choice among developers due to its simplicity and flexibility in managing application state. In this tutorial, we will explore the history, features, and examples of using Provider in your Dart applications.

History of Provider

Provider was created by Remi Rousselet and first released in 2019. It was designed to provide an easy and efficient way to manage state in Flutter applications. Since its release, it has gained popularity among Flutter developers and has become one of the most widely used state management solutions.

Features of Provider

Provider offers several key features that make it a powerful and flexible state management solution:

1. InheritedWidget

Provider leverages the power of Flutter's InheritedWidget to provide a simple and efficient way to propagate state changes throughout the widget tree. By using InheritedWidget, Provider ensures that only the necessary widgets are rebuilt when the state changes, resulting in better performance.

To use Provider, you need to wrap your widget tree with a Provider widget and specify the state you want to expose. Here's an example:

Provider<int>(
create: (_) => 0,
child: MyApp(),
)

In this example, we create a Provider that exposes an integer value of 0. This value can then be accessed by any widget in the widget tree below MyApp by using the Provider.of<int>(context) method.

2. ChangeNotifier

Provider also provides a ChangeNotifier class that can be used to notify listeners when the state changes. ChangeNotifier is an implementation of the Observer pattern and is commonly used with Provider to manage state.

Here's an example of using ChangeNotifier with Provider:

class Counter extends ChangeNotifier {
int _count = 0;

int get count => _count;

void increment() {
_count++;
notifyListeners();
}
}

In this example, we create a Counter class that extends ChangeNotifier. It has a count variable that represents the state and an increment method that updates the count and notifies listeners of the change.

To use this Counter class with Provider, we can wrap it with a ChangeNotifierProvider widget:

ChangeNotifierProvider(
create: (_) => Counter(),
child: MyApp(),
)

This allows any widget in the widget tree below MyApp to access the Counter instance and listen for state changes.

3. MultiProvider

Provider also provides a MultiProvider widget that allows you to combine multiple providers into a single widget. This is useful when you have multiple pieces of state that need to be exposed to different parts of your application.

Here's an example of using MultiProvider with Provider:

MultiProvider(
providers: [
Provider<int>(create: (_) => 0),
Provider<String>(create: (_) => "Hello"),
],
child: MyApp(),
)

In this example, we create a MultiProvider that exposes an integer value of 0 and a string value of "Hello". These values can then be accessed by any widget in the widget tree below MyApp using the respective Provider.of<int>(context) and Provider.of<String>(context) methods.

Examples of Provider Usage

Now let's take a look at some practical examples of using Provider in your Dart applications.

Example 1: Counter App

class Counter extends ChangeNotifier {
int _count = 0;

int get count => _count;

void increment() {
_count++;
notifyListeners();
}
}

class CounterApp extends StatelessWidget {

Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => Counter(),
child: MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Counter App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Count:',
style: TextStyle(fontSize: 24),
),
Consumer<Counter>(
builder: (context, counter, _) => Text(
counter.count.toString(),
style: TextStyle(fontSize: 48),
),
),
SizedBox(height: 16),
RaisedButton(
onPressed: () {
Provider.of<Counter>(context, listen: false).increment();
},
child: Text('Increment'),
),
],
),
),
),
),
);
}
}

In this example, we create a simple counter app that increments a count value when a button is pressed. The current count is displayed using the Consumer widget, which automatically rebuilds whenever the state changes.

Example 2: Theme Switcher

class ThemeProvider extends ChangeNotifier {
ThemeData _theme = ThemeData.light();

ThemeData get theme => _theme;

void toggleTheme() {
_theme = _theme == ThemeData.light() ? ThemeData.dark() : ThemeData.light();
notifyListeners();
}
}

class ThemeSwitcherApp extends StatelessWidget {

Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => ThemeProvider(),
child: Consumer<ThemeProvider>(
builder: (context, themeProvider, _) => MaterialApp(
theme: themeProvider.theme,
home: Scaffold(
appBar: AppBar(
title: Text('Theme Switcher'),
),
body: Center(
child: RaisedButton(
onPressed: () {
themeProvider.toggleTheme();
},
child: Text('Toggle Theme'),
),
),
),
),
),
);
}
}

In this example, we create a theme switcher app that allows the user to toggle between light and dark themes. The theme is managed by the ThemeProvider class, and the Consumer widget is used to rebuild the UI whenever the theme changes.

Conclusion

Provider is a powerful and flexible state management framework for Dart applications. It leverages Flutter's InheritedWidget and ChangeNotifier to provide a simple and efficient way to manage state. By using Provider, you can easily share and update state across your widget tree.