Providers are based on an observer (publish-subscribe) model.

Components and functions of Provider:

Listenable

As a publisher, you need to work with providers. Related components are as follows:

  • AddListener removeListener function and maintains a list of Listeners.
  • ChangeNotifier inherits from Listenable to provide the implemented publisher function and is often used in conjunction with The ChangeNotifierProvider.
  • ValueNotifier is based on ChangeNotifier and works with ValueListenableProvider. The difference is that ValueNotifier provides automatic notification of status changes of single variables without notifyListeners(). The disadvantage is that flexibility is sacrificed and only set methods of internal values are listened on.

Consumer ConsumerX

The role of the subscriber is also a convenient constructor, internally helping us to call provider.of (context) to get the ChangeNotifier, and to add itself to the subscriber.

You can also use provder.of (Conext) in widgets without using Consumer for the same effect.

Provider

Provider is implemented based on a DelegateWidget that provides a pair of Creat and Dispose to let us manage the data lifecycle, So with a Provider you don’t have to worry about memory release and data requests (this is a perfect substitute for StatefulWidget).

In addition, Providers provide different subclasses to accommodate various scenarios:

  • Provider: Provides creat and Dispose, and Inherited InheritedProvider, which is internally implemented based on InheritedWidget. However, the Provider does not have the ability to refresh child components, but can only be used to provide fixed data.
  • ListenableProvider: A low-level Provider with refresh sub-component functionality that needs to provide a publisher inheriting from Listenable to publish messages.
  • ChangeNotifierProvider: Inherited from ListenableProvider and used together with ChangeNotifier:
@override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<CustomChangeNotifier>(
      create: (BuildContext context) {
        return CustomChangeNotifier();
      },
      child: Consumer<CustomChangeNotifier>(
        builder: (builder: (context, notifier, _) {
      return new Column(
        children: <Widget>[
          new Expanded(child: new Center(child: new Text(notifier.count.toString()))),
          new Center(
            child: new FlatButton(
                onPressed: () {
                  notifier.add();
                },
                color: Colors.blue,
                child: new Text("+")))],); }Copy the code
  • FutureProvider: Supports async, provides a Future, waits for the Future to complete, and automatically refreshes the child part.
  • StreamProvider: Supports async, providing a Steam to act as a publisher and refreshing the child widgets when there is stream input.
  • ValueListenableProvider: supports a single variable. You need to provide a ValueNotifier to wrap data.
  • MultiProvider Is a combination of providers:
void main() {
  final counter = CounterModel();
  final textSize = 48;

  runApp(
    MultiProvider(
      providers: [
        Provider.value(value: textSize),
        ChangeNotifierProvider.value(value: counter)
      ],
      child: MyApp(),
    ),
  );
}
Copy the code
  • ProxyProviderX: ProxyProviderX: ProxyProviderX: ProxyProviderX: ProxyProviderX: ProxyProviderX

For example, if an image is uploaded, we can upload the image through a ChangeNotifierProvider to obtain the URL, and then intercept the uploaded URL through the ProxyProvider and upload it to the server.

/// The official sample
Widget build(BuildContext context) {
  returnMultiProvider( providers: [ ChangeNotifierProvider(create: (_) => Counter()), listing Provider<Counter, Translations>(update: (_, counter, __) => Translations(counter.value),),], child: Foo(),); }class Translations {
  const Translations(this._value);

  final int _value;

  String get title => 'You clicked $_value times';
}
Copy the code

Selector

In the fine-grained refresh of the business layer, Provider control alone is not enough, and in this case, Selector is needed. A Selector plays the same role as a Consumer, a subscriber, and can be used just like a Consummer, but with one more Selector.

Implementation principle:

The Selector inheritance in SingleChildStatefulWidget, in order to avoid repeated construction, rewrite the buildWithChild and widget for the cache, the data returned by the Selector Selector to equals to judge, And, of course, _shouldRebuild can do a mandatory build.

How to use:

Selector takes two generic variables Selector<T, S> and, via provider.of (context), gets the publisher, and S is used as the data type for whether or not the view needs to be rebuilt.

Selector<Translations, String>( selector: (context, provider) { return provider.title; // Return the changed data}, builder: (context, value, child) {print(" refresh "); return Text("$value"); },),Copy the code

Optimization experience:

Local refresh control

Provider has very good life cycle control, control the refresh range, and support the minimum principle as far as possible, which not only improves the refresh speed, but also optimizes data control, such as memory application and release frequency.

Lazy loading

Lazy loading refers to a lazy call to create, which is invoked only once during the lifetime of the provider, including network requests and data initialization. To disable lazy loading, set lazy to false.

The Dispose release

Providers attach great importance to memory control. In addition to dispose of various providers, ChangeNotifier also provides Dispose.