Based on the InheritedWidget, a simple data-driven model is implemented, and the model structure is as follows:

1. Data storage

Create an InheritedProvider using the InheritedWidget

import 'package:flutter/material.dart';
class InheritedProvider<T> extends InheritedWidget {
  final T data;
  InheritedProvider({@required this.data, Widget child}) : super(child: child);

  @override
  bool updateShouldNotify(InheritedProvider<T> oldWidget) {
    // Simply return true here, and each update calls didChangeDependencies on its descendants
    return true; }}Copy the code

2. Notification of change

The ChangeNotifier component of Flutter encapsulates the tool class ChangeNotifierProvider to respond to data changes and trigger UI updates.

class ChangeNotifierProvider<T extends ChangeNotifier> extends StatefulWidget {
  final Widget child;
  final T data; // Shared data model that requires inheritance from ChangeNotifier

  const ChangeNotifierProvider({
    Key key,
    this.child,
    this.data,
  }) : super(key: key);

  ///Provides methods for subtrees to get shared data
  static T of<T>(BuildContext context) {
    final provider =
        context.dependOnInheritedWidgetOfExactType<InheritedProvider<T>>();
    return provider.data;
  }

  @override
  _ChangeNotifierProviderState createState() =>
      _ChangeNotifierProviderState<T>();
}

class _ChangeNotifierProviderState<T extends ChangeNotifier>
    extends State<ChangeNotifierProvider<T>> {
  ///Rebuild the InheritedProvider if the data changes (the Model class calls notifyListeners)
  void update() {
    setState(() => {});
  }

  @override
  void didUpdateWidget(ChangeNotifierProvider<T> oldWidget) {
    ///When the Provider updates, if the old and new data are not "==", unbind the old data listener and add the new data listener
    if(widget.data ! = oldWidget.data) { oldWidget.data.removeListener(update); widget.data.addListener(update); }super.didUpdateWidget(oldWidget);
  }

  @override
  void initState() {
    widget.data.addListener(update);
    super.initState();
  }

  @override
  void dispose() {
    widget.data.removeListener(update);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    returnInheritedProvider<T>( data: widget.data, child: widget.child, ); }}Copy the code

Principle: use InheritedWidget as the parent node, when the data update, data model after ChangeNotifier associated, trigger _ChangeNotifierProviderState setState method, refresh the UI.

Encapsulation NotifyConsumer

Explicitly call directly ChangeNotifierProvider. Of access to Shared data semantic opacity, we will do a simple layer of packaging used for their children to get the data:

///Consumers who respond to changes in data
class NotifyConsumer<T> extends StatelessWidget {
  final Widget Function(BuildContext context, T value) builder;

  const NotifyConsumer({Key key, @required this.builder}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    returnbuilder( context, ChangeNotifierProvider.of<T>(context), ); }}Copy the code

3. Usage:

Create a shared data model:

///Shared data model
class CountModel extends ChangeNotifier {
  int _count = 0;
  int get count => _count;
  // provide the increment method
  void increase() {
    _count++;
    // Notify the listener (subscriber), rebuild the InheritedProvider, and update the status.notifyListeners(); }}Copy the code

How to use ChangeNotifierProvider:

import 'package:flutter/material.dart';
import 'package:test_interited/provider/change_notifier_provider.dart';
import 'package:test_interited/provider/notify_consumer.dart';
import 'package:test_interited/provider/test/count_model.dart';

class TestNotifierWidget extends StatefulWidget {
  const TestNotifierWidget({Key key}) : super(key: key);

  @override
  _TestNotifierWidgetState createState() => _TestNotifierWidgetState();
}

class _TestNotifierWidgetState extends State<TestNotifierWidget> {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: ChangeNotifierProvider<CountModel>(
            data: CountModel(),
            child: Builder(builder: (context) {
              return Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Builder(
                    builder: (context) {
                      // Get the shared data source
                      return NotifyConsumer<CountModel>(
                          builder: (context, value) {
                        return Text(value.count.toString());
                      });
                    },
                  ),
                  Builder(builder: (context) {
                    return RaisedButton(
                      child: Text('on the'),
                      onPressed: () {
                        // Get the shared model and increment the dataChangeNotifierProvider.of<CountModel>(context).increase(); }); })],); }))); }}Copy the code