作为一名前端,关于 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.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: [
Text('You have pushed the button this many times:'),
Provide(
builder: (context, child, counter) => Text(
'${counter.value}',
style: Theme.of(context).textTheme.display1,
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => Provide.value(context).increment(),
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
首先可以在入口函数里看到这段代码
var counter = Counter(); // 初始化 Counter
var providers = Providers(); // 初始化 Providers
providers.provide(Provider.value(counter));
runApp(
ProviderNode(
providers: providers,
child: MyApp(),
),
);
可以看到
Provider.value(counter)
源码:
abstract class Provider {
// 去除了很多 其他的代码
T get(BuildContext context);
Future dispose();
factory Provider.value(T value) => _ValueProvider(value);
}
// 这里就 返回了一个注册好了的数据
class _ValueProvider extends TypedProvider {
final T _value;
StreamController _streamController;
// 其实这里的 get 还是将你传进来的数据给返回出去了
@override
T get(BuildContext context) => _value;
@override
Stream stream(BuildContext context) {
final value = _value;
if (value is Listenable) {
_streamController ??= StreamController.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 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.value(counter));
class Providers {
/// 同样删除了 很多代码
Providers();
// 可以看到,执行这里 的 provide 实际上就是将 需要监听的数据都收集起来
void provide(Provider 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 createState() => _ProviderNodeState(
child: child, providers: providers, disposeProviders: dispose);
}
//
class _ProviderNodeState extends State {
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 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 getValue({ProviderScope scope}) {
return providers.getFromType(T, scope: scope) ??
parent?.getValue(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(
/// 可能会有很多人和我一样,疑惑这个 child 是干什么的
builder: (context, child, counter) => Text(
'${counter.value}',
style: Theme.of(context).textTheme.display1,
),
),
========
onPressed: () => Provide.value(context).increment(),
源码:
class Provide extends StatelessWidget {
final ValueBuilder builder;
final Widget child;
final ProviderScope scope;
const Provide({@required this.builder, this.child, this.scope});
/// 这里就是修改数据的 调用方法了,
/// 静态方法,所以需要传入的 泛型来进行 取值,并且返回
static T value(BuildContext context, {ProviderScope scope}) {
final provider = _InheritedProviders.of(context).getValue(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(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,发现这个停止更新了,惨,明明是最好用的那个