setState与局部刷新
setState想必对大家都很熟悉,你可以使用setState来刷新页面数据。setState源码如下:
@protected
void setState(VoidCallback fn) {
...
_element!.markNeedsBuild();
}
setState确实是一个大家耳熟能详的刷新页面的方法,但是setState有一个不好的地方,也就是它会将整个widget全部刷新。但是有时候我们只是更改页面中某个角落里的小数据,完全不需要全局刷新。因此,局部刷新对我们来说是一个非常好的解决办法。
InheritedWidget源码
在说我们的主角Provider之前,我们先来说说InheritedWidget。
InheritedWidget是一种从上到下数据共享的方式,你在根Widget上共享了一个数据,那个你在任意子Widget上都可以是使用这个数据。首先我们还是从源码进行分析:
abstract class InheritedWidget extends ProxyWidget {
/// 抽象的构造函数。这个构造函数使子类能够提供构造函数,从而使它们能够在构造表达式中使用。
const InheritedWidget({ Key? key, required Widget child })
: super(key: key, child: child);
@override
InheritedElement createElement() => InheritedElement(this);
/// 框架是否应该通知继承自这个小组件的组件。
/// 当这个小组件被重建时,有时我们需要重建继承自这个小组件的组件,但有时我们不需要。例如,如果这个小组件持有的数据与
/// oldWidget持有的数据相同,那么我们不需要重建继承了oldWidget持有的数据的小组件。
/// 框架通过调用这个函数来区分这些情况,并将之前在树中占据这个位置的widget作为一个参数。给定的widget被保证具有与此对象相同的
/// 运行时类型。
@protected
bool updateShouldNotify(covariant InheritedWidget oldWidget);
}
class InheritedElement extends ProxyElement {
/// 使用给定的部件作为其配置创建一个元素。
InheritedElement(InheritedWidget widget) : super(widget);
// get方法实现
@override
InheritedWidget get widget => super.widget as InheritedWidget;
final Map<Element, Object?> _dependents = HashMap<Element, Object?>();
@override
void _updateInheritance() {
// 检测生命周期
assert(_lifecycleState == _ElementLifecycle.active);
// 获取继承子组件
final Map<Type, InheritedElement>? incomingWidgets = _parent?._inheritedWidgets;
if (incomingWidgets != null)
_inheritedWidgets = HashMap<Type, InheritedElement>.of(incomingWidgets);
else
_inheritedWidgets = HashMap<Type, InheritedElement>();
_inheritedWidgets![widget.runtimeType] = this;
}
@override
void debugDeactivated() {
assert(() {
assert(_dependents.isEmpty);
return true;
}());
super.debugDeactivated();
}
@protected
Object? getDependencies(Element dependent) {
return _dependents[dependent];
}
@protected
void setDependencies(Element dependent, Object? value) {
_dependents[dependent] = value;
}
@protected
void updateDependencies(Element dependent, Object? aspect) {
setDependencies(dependent, null);
}
@protected
void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {
dependent.didChangeDependencies();
}
@override
void updated(InheritedWidget oldWidget) {
if (widget.updateShouldNotify(oldWidget))
super.updated(oldWidget);
}
@override
void notifyClients(InheritedWidget oldWidget) {
assert(_debugCheckOwnerBuildTargetExists('notifyClients'));
for (final Element dependent in _dependents.keys) {
assert(() {
// 检查它是否真的是我们的后代
Element? ancestor = dependent._parent;
while (ancestor != this && ancestor != null)
ancestor = ancestor._parent;
return ancestor == this;
}());
// 检查一下,这真的依赖于我们
assert(dependent._dependencies!.contains(this));
// 通知依赖进行更新
notifyDependent(oldWidget, dependent);
}
}
}