The underlying implementation of Provider data sharing for Flutter state management

Introduction

Senior Flutter engineers often start researching and learning from the simplest architecture.

What I bring to you today is the more important state management framework Provider in Flutter, and it is also a framework that every Flutter developer must learn. Provider is relatively powerful, and can easily implement functions such as one-click skinning and language switching. This article will teach you how to implement the simplest Provider framework step by step. Students who don’t know how to save it quickly and learn slowly.

Frame structure diagram

insert image description here

Principle analysis

Before explaining Provider, readers need to understand the functions of InheritedWidget and ChangeNotifier natively provided by Flutter in order to truly understand the shared data mechanism of Provider.

The role of InheritedWidget

InheritedWidget is an important Widget component provided by Flutter. It provides the ability to share data from top to bottom in the Widget tree. When InheritedWidget is used as the parent Widget, its internal child Widgets can all access the data saved in the parent Widget. .

Examples are as follows:

  1. Define a ShareWidget inherited from InheritedWidget , which defines a data to save shared data. Its ShareWidget code is as follows:
class ShareWidget extends InheritedWidget{
    
    
  const ShareWidget({
    
    super.key, required super.child,required this.data});
  final int data; //在子树中共享的数据

  
 //定义静态方法,数据共享给子Widget使用
  static ShareWidget? of(BuildContext context){
    
    
  //调用子控件的didChangeDependencies和rebuild方法
    return context.dependOnInheritedWidgetOfExactType<ShareWidget>();
  }
  //当回调决定当data发生变化时,通知子widget中使用date数据的widget执行build构建。
  @override
  bool updateShouldNotify(covariant ShareWidget oldWidget) {
    
    
    //当新旧数据发生变化时,通知子Widget重新构建
    return oldWidget.data != data;
  }

}

  1. The child Widget accesses the shared data data in the ShareWidget through the ShareWidget.of method . When the data data changes, the sub-Widget will be notified to rebuild, and the setState(){} method of the sub-Widget will be called internally.

The role of ChangeNotifier

I believe that all students are familiar with this subscriber mode of EventBus in Android. Flutter provides us with ChangeNotifier to implement the subscriber mode. You only need to inherit ChangeNotifier to realize data monitoring. Let's take a look at the internal source code of ChangeNotifier .

class ChangeNotifier implements Listenable {
    
    
  List listeners=[];
  @override
  void addListener(VoidCallback listener) {
    
    
     //添加监听器
     listeners.add(listener);
  }
  @override
  void removeListener(VoidCallback listener) {
    
    
    //移除监听器
    listeners.remove(listener);
  }
  
  void notifyListeners() {
    
    
    //通知所有监听器,触发监听器回调 
    listeners.forEach((item)=>item());
  }
....
}

ChangeNotifier inherits from Listenable, and internally provides three methods: addListener, removeListener, and notifyListeners . This is a typical subscriber model.

Provider's code implementation

  1. Define the InheritedProvider class to inherit from InheritedWidget . Generics are passed here. Facilitates sharing of all data types.
class InheritedProvider<T> extends InheritedWidget{
    
    
  const InheritedProvider({
    
    super.key, required Widget child,
    required this.data}):super(child: child);
  ///需要共享的数据
  final T data;

  @override
  bool updateShouldNotify(covariant InheritedProvider<T> oldWidget) {
    
    
   //数据变化时通知子widget重建
   return oldWidget.data != data;
  }

}

  1. Define ShopModel to inherit ChangeNotifier to provide data that needs to be shared. A collection of int types is defined here. When the data is added, notifyListeners () is called to notify all subscribers to update the data.
class ShopModel extends ChangeNotifier{
    
    
  final List<int> _items = [];
  List<int> get items =>_items;
  int get totalCount =>_items.fold<int>(0, (value, element)=>value+element);
  ///添加数据后,通知所有订阅者
  void addShop(int num){
    
    
    _items.add(num);
    notifyListeners();
  }

}

  1. The custom ChangeNotifierProvider inherits from StatefulWidget . Since ChangeNotifierProvider involves rebuilding the widget, it needs to inherit the stateful StatefulWidget.
class ChangeNotifierProvider<T extends ChangeNotifier> extends StatefulWidget{
    
    
  const ChangeNotifierProvider({
    
    super.key, required this.data, required this.child});
  final Widget child;
  final T data;


  static T of<T>(BuildContext context){
    
    
    var provider =context.dependOnInheritedWidgetOfExactType<InheritedProvider<T>>();
    return provider!.data;
  }
   @override
  State<ChangeNotifierProvider<T>> createState() =>_ChangeNotifierProviderState<T>();
}

The static method of is provided in ChangeNotifierProvider to provide sub-Widgets to obtain shared data T, where T refers to the ShopModel.

class _ChangeNotifierProviderState<T extends ChangeNotifier> extends State<ChangeNotifierProvider<T>>{
    
    
  ///更新重新构建wiget
  void update(){
    
    
    setState(() {
    
    
    });
  }
  @override
  void didUpdateWidget(covariant ChangeNotifierProvider<T> oldWidget) {
    
    
    if(oldWidget.data != widget.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) {
    
    
    ///这里使用InheritedProvider作为父widget,共享数据给子widget
    return InheritedProvider<T>(data: widget.data, child: widget.child);
  }

}

The data monitoring of data is registered in _ChangeNotifierProviderState. This article refers to ShopModel. When the ShopModel changes, all listeners are notified by calling the notifyListeners() method in ShopModel. Call the update method in _ChangeNotifierProviderState, the update method calls setState(){}, and calls the rebuild method of the current Widget to rebuild. _ChangeNotifierProviderState uses InheritedProvider as the parent widget to share data, that is, ShopModel to the child Widget.

  1. Let's look at the final usage.
ChangeNotifierProvider<CarModel>(
  data: ShopModel(),
  child: Builder(builder: (context) {
    
    
      return Center(child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Builder(builder: (context) {
    
    
            var cart =
              ChangeNotifierProvider.of<ShopModel>(context);
            return Text("计算结果:${cart.totalCount}");
          }),
          const SizedBox(
            height: 40,
          ),
          ElevatedButton(
            onPressed: () {
    
    
                ChangeNotifierProvider.of<CarModel>(context)
                  .addShop(10);
              },
            child: const Text('增加数字'))
        ],
      ),);
    }))

When we click the Add Number button, the ShopModel returned by ChangeNotifierProvider.of(context) calls the addShop method of ShopModel, and addShop calls notifyListeners, which is rebuilt through the listener ChangeNotifierProvider to display the latest data.

Summarize

InheritedWidget, ChangeNotifier, and Provider are widely used in Flutter and are relatively important. They are also components that Flutter developers must learn to use. In addition to these components that can share data, there are also excellent third-party frameworks such as Bloc that readers need to study and learn by themselves. Understand the idea of ​​framework implementation and learn how to build the framework. The focus of this article is not to write code, but to implement an excellent framework based on existing components, which is what the editor is pursuing.

at last

If you want to become an architect or want to break through the 20-30K salary range, then don't be limited to coding and business, but you must be able to select models, expand, and improve programming thinking. In addition, a good career plan is also very important, and the habit of learning is very important, but the most important thing is to be able to persevere. Any plan that cannot be implemented consistently is empty talk.

If you have no direction, here I would like to share with you a set of "Advanced Notes on the Eight Major Modules of Android" written by the senior architect of Ali, to help you organize the messy, scattered and fragmented knowledge systematically, so that you can systematically and efficiently Master the various knowledge points of Android development.
img
Compared with the fragmented content we usually read, the knowledge points of this note are more systematic, easier to understand and remember, and are arranged strictly according to the knowledge system.

Welcome everyone to support with one click and three links. If you need the information in the article, you can directly scan the CSDN official certification WeChat card at the end of the article to get it for free↓↓↓ PS

: There is also a ChatGPT robot in the group, which can answer your work or technical questions
picture

Guess you like

Origin blog.csdn.net/datian1234/article/details/131947380