zoukankan      html  css  js  c++  java
  • Provider 4.3.2+2 f

    • 概览
      Provider 4.3相比3.0系列版本有非常重大的改变,ValueDelegate被替代, MultiProviderchildren组织方式也进行了变更,采用Nested的方式实现,另外增加了context相关的语法糖read,watch,select.
    SingleChildWidget (nested.dart)
        SingleChildStatelessWidget (nested.dart)
            InheritedProvider (provider.dart)
                Provider (provider.dart)
                DeferredInheritedProvider (provider.dart)
                ListenableProvider (listenable_provider.dart) ..
                SubclassProvider (inherited_provider_test.dart) ...
            Consumer (consumer.dart)
            StateNotifierProvider (inherited_provider_test.dart)
            SingleChildStatelessWidgetMixin (nested.dart)
            SingleChildBuilder (nested.dart)
        SingleChildStatefulWidgetMixin (nested.dart)
        SingleChildStatefulWidget (nested.dart)
            Selector (selector.dart) ...
        Nested (nested.dart)
            MultiProvider (provider.dart)
    

    SingleChildWidget

    • 定义ElementSingleChildWidgetElementMixin协议
    • hook住mountactive方法,设置_parent(_NestedHookElement)

    SingleChildStatelessWidget

    • 改变默认的build行为,插入child dart abstract class SingleChildStatelessWidget extends StatelessWidget
      implements SingleChildWidget { ...
      @override
      Widget build(BuildContext context) => buildWithChild(context, _child);

    SingleChildWidgetElementMixin

    • 它是Element的一个mixin,用于在Element树更新时hook住mountactive方法,设置_parent(_NestedHookElement)
    • 其它相关的子类功能
    SingleChildWidgetElementMixin  
        _SingleChildStatefulMixinElement (nested.dart) //插入默认的child到tree中
        SingleChildInheritedElementMixin (nested.dart)//插入默认的child到tree中
        _NestedElement (nested.dart) //将`Nested`中的`children`使用`_NestedHook`嵌套的包裹,扁平化的child转换为widget树,同时持有每个child的`Element`放拜年后续修改
        SingleChildStatefulElement (nested.dart)
        SingleChildStatelessElement (nested.dart)
             _InheritedProviderElement (provider.dart)
    

    InheritedProvider

    • 它是通用的继承类型的provider的实现,类似InheritedWidget,不要直接使用它,可以通过它的子类Provider来实现,再它的任何子widget中可以通过Provider.of函数来互来获取它
    • 基本属性
    InheritedProvider({
        Key key,  
        Create<T> create, //配合lazy可实现懒加载
        T update(BuildContext context, T value), //配置更新value
        UpdateShouldNotify<T> updateShouldNotify,
        void Function(T value) debugCheckInvalidValueType,
        StartListening<T> startListening, //懒加载实现入口
        Dispose<T> dispose, //自定义state释放
        this.builder, //支持child widget动画,提升bloc动画构建性能
        bool lazy,  //是否懒加载`Create<T>`
        Widget child, //类似builder,不带动画
      })  
    
    • 它的具体实现是通过delegate来实现的,Delegate来代理执行它的State状态代理,并执行相关的回调来初始化或释放value
    _Delegate (provider.dart)
        _CreateInheritedProvider (provider.dart) //InheritedProvider采用create方式初始化value的代理,在value的get方法中实现了懒加载create创建
        _ValueInheritedProvider (provider.dart)  //InheritedProvider采用value直接赋值的方式初始化
        _DeferredDelegate (provider.dart)
            _CreateDeferredInheritedProvider (provider.dart)
            _ValueDeferredInheritedProvider (provider.dart)
    
    • 最终通过_InheritedProviderScope继承InheritedWidget的功能,_InheritedProviderScope持有了InheritedProvider对象
      @override
      _InheritedProviderElement<T> createElement() {
        return _InheritedProviderElement<T>(this);
      }
    
      @override
      Widget buildWithChild(BuildContext context, Widget child) { ...
        return _InheritedProviderScope<T>(
          owner: this,
          child: builder != null
              ? Builder(
                  builder: (context) => builder(context, child),
                )
              : child,
        );
      }
    
    • 取值过程
    static T of<T>(BuildContext context, {bool listen = true}) { ...
        /// 此处的`inheritedElement`为上面`_InheritedProviderScope`所对应的Element,它通过`InheritedProvider`的`Delegate`对象间接的持有的value, `T get value => _delegateState.value;`
      
        final inheritedElement = _inheritedElementOf<T>(context);
        
        /// 如需要监听Provider变更事件,则将传入的Context添加到`inheritedElement`的依赖列表中,当下次更新的时候会触发`context`的更新
        if (listen) {
          context.dependOnInheritedElement(inheritedElement);
        }
        return inheritedElement.value;
      }
      
      static _InheritedProviderScopeElement<T> _inheritedElementOf<T>(
        BuildContext context,
      ) {  ... 
        return inheritedElement;
      }
    

    Provider

    • 注册数据到它所在的Context中,在之前的所有child中可以通过Provider.of<Type>(context)获取对应的数据
    • 它有两种创建方式,一种直接传入value,但存的获取数据,在Provider释放时不会value无法接受到它的dispose事件
    • 为了避免类似于Stream流对象,内存泄漏问题,提供了create方式创建,可以监听dispose事件在内部对相关的资源进行释放。
    • example:
    /// class Model {
    ///   void dispose() {}
    /// }
    ///
    /// class Stateless extends StatelessWidget {
    ///   @override
    ///   Widget build(BuildContext context) {
    ///     return Provider<Model>(
    ///       create: (context) =>  Model(),
    ///       dispose: (context, value) => value.dispose(),
    ///       child: ...,
    ///     );
    ///   }
    /// }
    
    • MultiProvider: 它通过Nested控件提供了一个扁平化的WidgetTree构建方式,再3.0x的的系列版本中它时通过递归的嵌套Child来实现的.
    /// MultiProvider(
    ///   providers: [
    ///     Provider<Something>(create: (_) => Something()),
    ///     Provider<SomethingElse>(create: (_) => SomethingElse()),
    ///     Provider<AnotherThing>(create: (_) => AnotherThing()),
    ///   ],
    ///   child: someWidget,
    /// )
    

    DeferredInheritedProvider

    • 异步value的providers
    FutureProvider (async_provider.dart) //接收一个Future,并在其进入complete状态时更新依赖它的组件。
    StreamProvider (async_provider.dart) //监听流,并暴露出当前的最新值
    ValueListenableProvider (value_listenable_provider.dart) //监听ValueListenable,并且只暴露出ValueListenable.value。
    DeferredSubclassProvider (inherited_provider_test.dart)
    

    ListenableProvider

    • 注册一个Notifier的对象到Context中,可以实现连个widget之间的数据相互传递,比如Provider中的counter示例
    ChangeNotifierProvider (change_notifier_provider.dart)
    
    • 示例
        ///1. 注册
        MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (_) => Counter()),
          ],
          child: MyApp(),
        ),
        ///2. 使用 
        class XXXChildWidget ....
        Provider.of<Counter>(context).increment();
        
    

    Consumer

    • 用于处理多个Provider中的数据依赖,一种语法糖,可以很方便的将多个bloc的数据进行关联,但仅限于再MultiProvider中使用
    /// MultiProvider(
    ///   providers: [
    ///     Provider(create: (_) => Foo()),
    ///     Consumer<Foo>(
    ///       builder: (context, foo, child) =>
    ///         Provider.value(value: foo.bar, child: child),
    ///     )
    ///   ],
    /// );
    

    Nested

  • 相关阅读:
    Dom对象和jQuery对象区别 jQuery对象转换为Dom对象、、Dom对象转换为jquery对象
    jquery 1,2,3三个版本的下载、区别/以及jquery使用步骤,jQuery入口函数
    2021年3月4日 第一周开课博客
    2021年3月3日
    2021年3月2日
    2021年2月24日 记账本开发07
    2021年2月23日 记账本开发06
    2021年2月22日 记账本开发05
    程序员修炼之道读书笔记03
    2021年2月21日 记账本开发04
  • 原文地址:https://www.cnblogs.com/wwoo/p/provider-4322-f.html
Copyright © 2011-2022 走看看