flutter provide 学习笔记

作为一名前端,关于 flutter 的 状态管理器 Provide 的使用方法其实不是很能理解,因为这里出现了泛型

所以决定去看看 Provide,了解使用 Provide 中的泛型到底是怎么被使用的,同时加深对于 Dart 的理解

首先,是 github 上的 example 源码,我将会基于这个来进行学习

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:provide/provide.dart';

void main() {
  var counter = Counter();
  Timer.periodic(
    const Duration(seconds: 5),
    (timer) => counter.increment(),
  );
  var providers = Providers();
  providers.provide(Provider<Counter>.value(counter));
  runApp(
    ProviderNode(
      providers: providers,
      child: MyApp(),
    ),
  );
}

/// 这里定义了一个 状态管理的 Model 对象
class Counter extends ChangeNotifier {
  int value = 0;

  void increment() {
    value += 1;
    /// 通知 监听者 去更新数据
    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Demo Home Page'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('You have pushed the button this many times:'),
            Provide<Counter>(
              builder: (context, child, counter) => Text(
                    '${counter.value}',
                    style: Theme.of(context).textTheme.display1,
                  ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => Provide.value<Counter>(context).increment(),
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

首先可以在入口函数里看到这段代码

  var counter = Counter();  // 初始化 Counter 
  var providers = Providers();  // 初始化 Providers
  providers.provide(Provider<Counter>.value(counter));
  runApp(
    ProviderNode(
      providers: providers,
      child: MyApp(),
    ),
  );

可以看到 

Provider<Counter>.value(counter)

源码:

abstract class Provider<T> {
  //  去除了很多 其他的代码
  T get(BuildContext context);

  Future<void> dispose();
  factory Provider.value(T value) => _ValueProvider(value);

}
// 这里就 返回了一个注册好了的数据
class _ValueProvider<T> extends TypedProvider<T> {
  final T _value;
  StreamController _streamController;

  // 其实这里的 get 还是将你传进来的数据给返回出去了
  @override
  T get(BuildContext context) => _value;

  @override
  Stream<T> stream(BuildContext context) {
    final value = _value;
    if (value is Listenable) {
      _streamController ??= StreamController<T>.broadcast();
      value.addListener(_streamListener);
    } else {
      throw UnsupportedError(
          'Cannot create stream from a value that is not Listenable');
    }

    return _streamController.stream;
  }

  _ValueProvider(this._value);

 // 注销,源码中如果这个 provide 不使用了,就会去调用这里的 dispose 执行注销
  @override
  Future<void> dispose() async {
    final value = _value;
    if (value is Listenable) {
      value.removeListener(_streamListener);
    }
    await _streamController?.close();
  }

  void _streamListener() {
    _streamController?.add(_value);
  }
}

而 关于  这里 数据的收集

  var providers = Providers();
  // 收集  监听的 数据 见下面
  providers.provide(Provider<Counter>.value(counter));
class Providers {
  /// 同样删除了 很多代码
  Providers();

  // 可以看到,执行这里 的 provide 实际上就是将 需要监听的数据都收集起来
  void provide<T>(Provider<T> provider, {ProviderScope scope}) {
    assert(provider.type == T);

    _providersForScope(scope)[T] = provider;
  }
}

接着就是挂载到 根组件上面了

    ProviderNode(
      providers: providers,
      child: MyApp(),
    ),

关于这个 ProviderNode ,可以发现这个实际上是一个 Widget

class ProviderNode extends StatefulWidget {
  /// 对应包裹起来的子组件
  final Widget child;

  /// 所有的状态,就是在上面被收集的
  final Providers providers;

  final bool dispose;

  /// Constructor.
  const ProviderNode(
      {@required this.child, @required this.providers, this.dispose = true});

  // statefulWidget 执行 这里的 State,并返回
  @override
  State<StatefulWidget> createState() => _ProviderNodeState(
      child: child, providers: providers, disposeProviders: dispose);
}
//
class _ProviderNodeState extends State<ProviderNode> {
  final Widget child;
  final Providers providers;

  /// Whether or not to dispose the providers when this node is removed
  /// from the tree.
  final bool disposeProviders;

  _ProviderNodeState(
      {@required this.child,
      @required this.providers,
      @required this.disposeProviders});

  @override
  Widget build(BuildContext context) {
    return _InheritedProviders(
        child: child,
        providers: providers,
        parent: _InheritedProviders.of(context));
  }

  @override
  Future<void> dispose() async {
    super.dispose();
    if (disposeProviders) {
      await providers.dispose();
    }
  }
}
/// 这里就是 数据向下传导的关键了,就好像是 React 的 Provide 组件一样
/// 这里的代码还是很重要的,我就没有进行删除 
/// 这里继承了一个InheritedWidget, InheritedWidget是Flutter的一个功能型的Widget基类

/// 它能有效地将数据在当前Widget树中向它的子widget树传递

class _InheritedProviders extends InheritedWidget {
  final _InheritedProviders parent;
  final Providers providers;
  const _InheritedProviders({Widget child, this.providers, this.parent})
      : super(child: child);

  /// Finds the closest _InheritedProviders widget abocve the current widget.
  static _InheritedProviders of(BuildContext context) {
    /// inheritFromWidgetOfExactType 函数
    /// 获取最近的给定类型的 Widget,该widget必须是InheritedWidget的子类
    /// 同时接收到 对应 数据的子组件也会在 这里的数据变化的时候进行更新
    /// 没错,这段函数 就是在 flutter 内部定义的
    final widget = context.inheritFromWidgetOfExactType(_InheritedProviders);
    return widget is _InheritedProviders ? widget : null;
  }

  @override
  bool updateShouldNotify(_InheritedProviders oldWidget) {
    return parent?.updateShouldNotify(oldWidget.parent) ??
        false || providers != oldWidget.providers;
  }

  /// 下面会有 调用的时候,就是返回 相应的状态
  /// 在 调用 Model 类进行修改,以及 获得这里的数据并渲染,都会用到这个
  /// 这个时候 就是 根据传入的 泛型 来获取 对应 的 Model
  ///  (无论是 数据 还是操作 都已经放在了这个 Model 之中)
  Provider<T> getValue<T>({ProviderScope scope}) {
    return providers.getFromType(T, scope: scope) ??
        parent?.getValue<T>(scope: scope);
  }

  /// Needed because this works at runtime for ProvideMulti.
  Provider getFromType(Type type, {ProviderScope scope}) {
    return providers.getFromType(type, scope: scope) ??
        parent?.getFromType(type, scope: scope);
  }
}

接着就是使用了,其实这里才是真正用到 泛型的 地方

获取数据以及修改数据:

Provide<Counter>(
   /// 可能会有很多人和我一样,疑惑这个 child 是干什么的
   builder: (context, child, counter) => Text(
       '${counter.value}',
       style: Theme.of(context).textTheme.display1,
       ),
),

========

 onPressed: () => Provide.value<Counter>(context).increment(),

源码:

class Provide<T> extends StatelessWidget {

  final ValueBuilder<T> builder;
  final Widget child;
  final ProviderScope scope;
  const Provide({@required this.builder, this.child, this.scope});

  /// 这里就是修改数据的 调用方法了,
  /// 静态方法,所以需要传入的 泛型来进行 取值,并且返回
  static T value<T>(BuildContext context, {ProviderScope scope}) {
    final provider = _InheritedProviders.of(context).getValue<T>(scope: scope);
    assert(provider != null);

    return provider.get(context);
  }

  /// 可以看到,这里的child 实际上是 你初始化穿进去的东西原封不动的 给你了
  /// 因为有的 widget 是很复杂且不变的,可以通过这里 减少 widget 的重复构建
  @override
  Widget build(BuildContext context) {

     /// 正如上文所讲的 ,flutter 内部自定义了 一个 上下文结构,这里就是调用 并获取的地方
     /// 没有看过的可以 往上面找 _InheritedProviders 类
     /// 就好像是 Theme.of(context) 一样的原理

    final provider = _InheritedProviders.of(context).getValue<T>(scope: scope);
    final value = provider.get(context);
    final listenable = _getListenable(provider, value);

    if (provider is Listenable) {
      return ListeningBuilder(
        listenable: listenable,
        child: child,
        builder: (buildContext, child) =>
            builder(buildContext, child, provider.get(context)),
      );
    } else if (value is Listenable) {
      return ListeningBuilder(
        listenable: listenable,
        child: child,
        builder: (buildContext, child) => builder(buildContext, child, value),
      );
    }
  }
}

以上,就是梳理了一下 我这次学习的内容了,有错误的也希望 同学们可以指出来,

ps:看了相关的 issue,发现这个停止更新了,惨,明明是最好用的那个

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章