Introduction
This article explains how the state is managed in Flutter. There is a method you already know about, that is, scoped models. Provider is also a state management technique that is developed by the community, not by Google; however, Google highly encourages it. Now, let’s see Provider in detail.
A brief explanation of provider with real-time example
Scenario 1
Everyone of you have created a list of customers or products in some programming language. Now, assume you add a new customer or product dynamically in that list. What you need is to refresh the list to view the newly added item into the list. Every time you add a new item, you need to refresh the list. Doing the same many times reduces the performance of the app. State Management is a concept to handle such a situation to improve the performance.
Scenario 2
IMagine that you have a list on page 1 and you will add a new item on page 2. So, the newly added items will not be reflected on page 1 until you fetch the list again. Here, Provider will help you to manage such situation where any update in the list will be notified everywhere it will be used and automatically update with changes as and when needed.
You will find terms like ChangeNotifier, notifyListeners, ChangeNotifierProvider, Consumer, etc. These are the parts of Provider to manage the above scenario.
So, let’s understand it by implementing the above example.
Steps
Step 1
The first and most basic step is to create a new application in Flutter. If you are a beginner, you can check my blog
Create a first app in Flutter. I have created an app named “flutter_statemanagement_using_provider”.
Step 2
Add a Dependency in the pubspec.yaml file.
- dependencies:
- flutter:
- sdk: flutter
- cupertino_icons: ^0.1.2
- provider: ^3.0.0+1
Step 3
Now, create one folder under the lib folder and name it as providers. The Providers folder will contain all the data related files. Now, create one file under providers and name it as customers.dart. Below is the code of the customers.dart file. Please read the comments in the code. It will give you a detailed explanation.
-
- import 'package:flutter/foundation.dart';
-
- class CustomerList with ChangeNotifier {
-
- List<Customer> customers = [];
- CustomerList({this.customers});
-
- getCustomers() => customers;
- void addCustomer(Customer customer) {
- customers.add(customer);
- notifyListeners();
- }
-
- void removeCustomer(int index) {
- customers.removeAt(index);
- notifyListeners();
- }
- }
-
- class Customer {
-
- String name;
- int age;
- Customer({this.name, this.age});
- }
Step 4
Now, create another folder under lib, named pages. This folder will contain all the pages of the app. Now, create a file under this folder named as new_customer.dart. We are going to create a form to add new customers. Below is the code of the new_customer.dart file. I have created a form to get the customer name and age. Please read the comments in the code; it will give you a detailed explanation.
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:flutter_statemanagement_using_provider/providers/customers.dart';
-
- class NewCustomer extends StatefulWidget {
- final customerList;
- NewCustomer({Key key, this.customerList}) : super(key: key);
-
- @override
- _NewCustomerState createState() => _NewCustomerState();
- }
-
- class _NewCustomerState extends State<NewCustomer> {
- final GlobalKey<FormState> _formStateKey = GlobalKey<FormState>();
- String _name;
- String _age;
-
- final _nameController = TextEditingController(text: '');
- final _ageController = TextEditingController(text: '');
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: Text("New Customer"),
- ),
- body: SingleChildScrollView(
- scrollDirection: Axis.vertical,
- child: Column(
- children: <Widget>[
- Form(
- key: _formStateKey,
- autovalidate: true,
- child: Column(
- children: <Widget>[
- Padding(
- padding: EdgeInsets.only(left: 10, right: 10, bottom: 5),
- child: TextFormField(
- onSaved: (value) {
- _name = value;
- },
- controller: _nameController,
- decoration: InputDecoration(
- focusedBorder: new UnderlineInputBorder(
- borderSide: new BorderSide(
- width: 2,
- style: BorderStyle.solid,
- )),
- labelText: "Customer Name",
- icon: Icon(Icons.account_box, color: Colors.green),
- fillColor: Colors.white,
- labelStyle: TextStyle(
- color: Colors.green,
- ),
- ),
- ),
- ),
- Padding(
- padding: EdgeInsets.only(left: 10, right: 10, bottom: 5),
- child: TextFormField(
- onSaved: (value) {
- _age = value;
- },
- keyboardType: TextInputType.phone,
- inputFormatters: <TextInputFormatter>[
- WhitelistingTextInputFormatter.digitsOnly
- ],
- controller: _ageController,
- decoration: InputDecoration(
- focusedBorder: new UnderlineInputBorder(
- borderSide: new BorderSide(
- color: Colors.green,
- width: 2,
- style: BorderStyle.solid)),
- labelText: "Age",
- icon: Icon(
- Icons.phone_android,
- color: Colors.green,
- ),
- fillColor: Colors.white,
- labelStyle: TextStyle(
- color: Colors.green,
- ),
- ),
- ),
- ),
- ],
- ),
- ),
- Divider(),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: <Widget>[
- RaisedButton(
- color: Colors.green,
- child: Text(
- ('SAVE'),
- style: TextStyle(color: Colors.white),
- ),
- onPressed: () {
- _formStateKey.currentState.save();
-
- widget.customerList.addCustomer(
- Customer(name: _name, age: int.parse(_age)));
- Navigator.of(context).pop();
- },
- ),
- ],
- )
- ],
- ),
- ),
- );
- }
- }
Step 5
Now, in main.dart, we have created a list of customers. Please note that in main.dart file, we have implemented listener and that is the important part of this article so carefully read the comment in the code. It will explain how it works.
- import 'package:flutter/material.dart';
- import 'package:flutter_statemanagement_using_provider/pages/new_customer.dart';
- import 'package:flutter_statemanagement_using_provider/providers/customers.dart';
- import 'package:provider/provider.dart';
-
- void main() => runApp(MyApp());
-
- class MyApp extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- theme: ThemeData(
- primarySwatch: Colors.blue,
- ),
-
- home: ChangeNotifierProvider<CustomerList>(
-
- builder: (_) => CustomerList(
- customers: [
- Customer(name: "Parth Patel", age: 30),
- ],
- ),
- child: MyHomePage(title: 'Provider State Management'),
- ),
-
- );
- }
- }
-
- class MyHomePage extends StatefulWidget {
- MyHomePage({Key key, this.title}) : super(key: key);
- final String title;
-
- @override
- _MyHomePageState createState() => _MyHomePageState();
- }
-
- class _MyHomePageState extends State<MyHomePage> {
- @override
- Widget build(BuildContext context) {
-
-
- final customerList = Provider.of<CustomerList>(context);
- return Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: ListView.builder(
- itemCount: customerList.getCustomers().length,
- itemBuilder: (context, index) {
- return ListTile(
- title: Text('${customerList.getCustomers()[index].name}'),
- subtitle: Text('${customerList.getCustomers()[index].age}'),
- trailing: Container(
- width: 50,
- child: Row(
- children: <Widget>[
- IconButton(
- icon: Icon(
- Icons.delete,
- color: Colors.red,
- ),
- onPressed: () {
-
- customerList.removeCustomer(index);
- },
- )
- ],
- ),
- ),
- );
- },
- ),
- floatingActionButton: FloatingActionButton(
- onPressed: () {
-
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => NewCustomer(customerList: customerList)),
- );
- },
- child: Icon(Icons.add),
- ),
- );
- }
- }
Step 6
Hurray…. Run the app and test it. :)))
Conclusion
State Management is one of the key parts of performance improvement of the app and Provider is the best approach to achieve it. Previously, state was managed by scoped models which are not so effective so, it is recommended to use Provider as and when needed.