Open In App

Flutter – Provider Package

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(
  create: (context) => DataModel(),
  child: ...
)
@override
 Widget build(BuildContext context) {
   return Consumer<DataModel>(
     builder: (context, data, child) => DataWidget(par1: par1, par2: par2),
     child: Text(data.first),
   );
 }
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(),)
MultiProvider(
  providers: [
    Provider<Model1>(create: (context) => Model1()),
    StreamProvider<Model2>(create: (context) => Model2()),
    FutureProvider<Model3>(create: (context) => Model3()),
  ],
  child: someWidget,
)
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.
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>.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 classes.

For using the provider package we need to add the provider package to the dependencies section of pubspec.yaml and click on the get button to get the dependencies.



dependencies:
  flutter:
    sdk: flutter
  provider: ^4.3.2+4 #ADD

We will be looking at a simple example app

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.




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.




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();
  }
}

Now that the model is defined we will clean up the main.dart as




import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'model/item_data.dart';
import 'home.dart';
  
void main() {
  runApp(MyApp());
}
  
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => ItemData(),
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Provider Demo',
        theme: ThemeData(
          primarySwatch: Colors.green,
        ),
        home: Home(),
      ),
    );
  }
}

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 on the top.

The item_list.dart creates a ListView builder of the data coming from the list. It uses the Consumer to get the data.




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),
                    ),
                  ],
                ),
              ),
            ),
          );
        },
      );
    });
  }
}

At last, we will be writing the code for the home.dart file which contains the data that is to be displayed on the screen. It also contains a TextField and a button to add the data to the list.

Output:

Apart from Provider, there are other State Management also available such as –


Article Tags :