美文网首页flutter
Flutter Provider实现原理

Flutter Provider实现原理

作者: 出来遛狗了 | 来源:发表于2021-12-08 16:08 被阅读0次

    Provider源码分析

    ChangeNotifierProvider、ChangeNotifier、Consumer的关系


    关系

    一、ChangeNotifierProvider

    1、ChangeNotifierProvider的父类ListenableProvider,ListenableProvider中实现了_startListening方法,_startListening主要是将Element的刷新方法添加到ChangeNotifier中的_listeners中

    class ListenableProvider<T extends Listenable?> extends 
      ListenableProvider({
      ...
      }) : super(
              key: key,
              startListening: _startListening,
             ...
            );
      static VoidCallback _startListening(
        InheritedContext e,
        Listenable? value, //该对象其实就是ChangeNotifier对象
      ) {
        ///添加element刷新方法
        value?.addListener(e.markNeedsNotifyDependents);
        return () => value?.removeListener(e.markNeedsNotifyDependents);
      }
    

    2、ListenableProvider将startListening传入其父类InheritedProvider,InheritedProvider主要是创建delegate = _CreateInheritedProvider。这个delegate就是_CreateInheritedProvider中delegate.startListening中的delegate

    二、ChangNotifier

    1、ChangNotifier负责更新UI


    image.png

    ChangeNotifier中notifyListeners,通过遍历_listeners,实现强制刷新UI

    void notifyListeners() {
        assert(_debugAssertNotDisposed());
        if (_count == 0)
          return;
        _notificationCallStackDepth++;
    
        final int end = _count;
        for (int i = 0; i < end; i++) {
          try {
            _listeners[i]?.call();
          } catch (exception, stack) {
           ...
        }
    

    三、Consumer

    1、Consumer:包裹待刷新UI,在buildWithChild中将Provider.of<T>(context)传入builder方法


    原理
    class Consumer<T> extends SingleChildStatelessWidget
    ...
     @override
      Widget buildWithChild(BuildContext context, Widget? child) {
        return builder(
          context,
          Provider.of<T>(context),//传入ChangeNotifier
          child,
        );
      }
    

    2、解析 Provider.of<T>(context)
    Provider.of<T>(context)是获取ChangeNotifier对象的方法
    Provider.of中通过传入的context,获取父视图为inheritedElement的对象
    获取到inheritedElement,通过inheritedElement.getValue的方式获取ChangeNotifier对象

    static T of<T>(BuildContext context, {bool listen = true}) {
       
      ///获取父视图为inheritedElement的对象
        final inheritedElement = _inheritedElementOf<T>(context); 
    
        if (listen) {
         context.dependOnInheritedWidgetOfExactType<_InheritedProviderScope<T?>>();
        }
      ///调用inheritedElement.getValue获取Provider对象的对象
        final value = inheritedElement?.value;
        ...
        return value as T;
      }
    

    7、继续查看inheritedElement?.value。通过断点可以进入_CreateInheritedProvider 类中get Value方法。调用startListening将当前Consumer包裹的element添加到Prorivder的_listeners数组中

    class _CreateInheritedProvider<T> extends _Delegate<T> {
      ...
      @override
      T get value {
         ...
        element!._isNotifyDependentsEnabled = false;
        ///调用startListening将当前Consumer包裹的element添加到ChangeNotifier的_listeners数组中
        _removeListener ??= delegate.startListening?.call(element!, _value as T);
        element!._isNotifyDependentsEnabled = true;
        assert(delegate.startListening == null || _removeListener != null);
        return _value as T;
      }
    

    四、总结

    通过调用notifyListeners()来刷新所有Consumer完整的Provider执行流程大概就是这样,流程图如下


    完整流程图

    相关文章

      网友评论

        本文标题:Flutter Provider实现原理

        本文链接:https://www.haomeiwen.com/subject/gnmsxrtx.html