flutter InheritedWidget机制

Posted Android部落格

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flutter InheritedWidget机制相关的知识,希望对你有一定的参考价值。

个人网站:chengang.plus

1、用法

用法示例:

class InheritedData extends InheritedWidget { final String data;
InheritedData({ this.data, Widget child, }) : super(child: child);
static InheritedData of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType<InheritedData>(); }
@override bool updateShouldNotify(InheritedData old) => true;}
class TestInheritedDataWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Center( child: Text( "${InheritedData.of(context).data}", style: TextStyle(fontSize: 18, color: Colors.pink), ), ); }}
class ParentWidget extends StatefulWidget { @override _ParentWidgetState createState() => _ParentWidgetState();}
class _ParentWidgetState extends State<ParentWidget> { var data = "you are beautiful";
@override Widget build(BuildContext context) { return Scaffold( body: GestureDetector( child: Container( color: Colors.cyan, width: double.infinity, child: InheritedData( data: data, child: TestInheritedDataWidget(), ), ), onTap: _buttonClicked, ), ); }
_buttonClicked() { setState(() { data = "in white"; }); }}

2、ProxyWidget

InheritedWidget继承自ProxyWidget,在ProxyWidget中createElement调用的时候,创建了一个InheritedElement对象。

2.1 InheritedElement

InheritedElement继承自ProxyElement,ProxyElement继承自ComponentElement,ComponentElement继承自Element。

在InheritedElement中定义了一个全局Map对象:

final Map<Element, Object> _dependents = HashMap<Element, Object>();

同时还定义了一个_updateInheritance方法。在Element和 InheritedElement中都有定义:

Element

void _updateInheritance() { _inheritedWidgets = _parent?._inheritedWidgets;}

Map<Type, InheritedElement> _inheritedWidgets定义在Element中,是一个全局变量。

InheritedElement

@overridevoid _updateInheritance() { final Map<Type, InheritedElement> incomingWidgets = _parent?._inheritedWidgets; if (incomingWidgets != null) _inheritedWidgets = HashMap<Type, InheritedElement>.from(incomingWidgets); else _inheritedWidgets = HashMap<Type, InheritedElement>(); _inheritedWidgets[widget.runtimeType] = this;}

InheritedElement中这个方法的主要逻辑是:先判断当前Element的_inheritedWidgets是否存在,不存在,新建一个,否则将已有的添加到_inheritedWidgets中,同时将当前Element添加到_inheritedWidgets中。

Element中的_updateInheritance方法被执行意味着,所有的Widget对应的Element都持有一个_inheritedWidgets,而InheritedWidget的child就可以通过Element的_updateInheritance方法直接持有InheritedElement。

2.2 保存InheritedElement节点

那么_updateInheritance是哪里调用的呢?

参考之前的文章《flutter 绘制过程 系列2-布局》,在Element类的mount方法中,会调用_updateInheritance方法,最终就调用到这里了。

3、ProxyElement中更新

当InheritedWidget中的data被setState更新之后,依赖data的Widget也会被更新。

3.1 ProxyElement update方法

@overridevoid update(ProxyWidget newWidget) { final ProxyWidget oldWidget = widget; super.update(newWidget); updated(oldWidget); _dirty = true; rebuild();}

到updated方法,在InheritedElement方法中:

InheritedElement

@overridevoid updated(InheritedWidget oldWidget) { if (widget.updateShouldNotify(oldWidget)) super.updated(oldWidget);}

如果我们InheritedWidget中的updateShouldNotify返回为true的话,会执行到InheritedElement的updated方法中:

@protectedvoid updated(covariant ProxyWidget oldWidget) { notifyClients(oldWidget);}

notifyClients执行到了子类InheritedElement的notifyClients方法。

3.2 InheritedElement notifyClients方法

@overridevoid notifyClients(InheritedWidget oldWidget) { for (final Element dependent in _dependents.keys) { notifyDependent(oldWidget, dependent); }}

这里的_dependents里面保存的是依赖InheritedWidget数据的节点。

3.3 _dependents保存依赖数据的Element

本章最开始的时候InheritedData提供了一个静态的of方法,依赖者(InheritedWidget的child Widget)调用dependOnInheritedWidgetOfExactType方法。在Element类中实现,BuildContext类中定义:

Element实现了BuildContext接口

Element

@overrideT dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object aspect}) { final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T]; if (ancestor != null) { return dependOnInheritedElement(ancestor, aspect: aspect) as T; } _hadUnsatisfiedDependencies = true; return null;}

这里先找到InheritedElement,通过_inheritedWidgets的key(runtimeType)找到对应的value(InheritedElement)。接下来调用dependOnInheritedElement方法:

Element

@overrideInheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect }) { _dependencies ??= HashSet<InheritedElement>(); _dependencies.add(ancestor); ancestor.updateDependencies(this, aspect); return ancestor.widget;}

在Element类中,先判断_dependencies是否为空,为空的话新建一个HashSet,把这个InheritedElement添加进去,然后执行updateDependencies方法。这个this指代的就是InheritedWidget的child Widget的Element。

这个updateDependencies定义在对应的InheritedElement类中:

InheritedElement

@overridevoid updateDependencies(Element dependent, Object aspect) { final Set<T> dependencies = getDependencies(dependent) as Set<T>; if (dependencies != null && dependencies.isEmpty) return;  if (aspect == null) { setDependencies(dependent, HashSet<T>()); } else { setDependencies(dependent, (dependencies ?? HashSet<T>())..add(aspect as T)); }}
@protectedvoid setDependencies(Element dependent, Object value) { _dependents[dependent] = value;}

到这里基本上清楚了基本的脉络,_dependents里面保存的就是是InheritedWidget的child Widget的Element。

3.4 提醒依赖Element更新

回到InheritedElement notifyClients方法,这里会遍历_dependents,然后执行notifyDependent方法:

InheritedElement

@protectedvoid notifyDependent(covariant InheritedWidget oldWidget, Element dependent) { dependent.didChangeDependencies();}
@mustCallSupervoid didChangeDependencies() { markNeedsBuild();}

到这里重新绘制渲染依赖InheritedWidget数据的Widget。


以上是关于flutter InheritedWidget机制的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 数据共享 InheritedWidget

Flutter:我应该如何使用 InheritedWidget?

flutter系列InheritedWidget介绍

Flutter核心类分析深入理解数据共享InheritedWidget

Flutter核心类分析深入理解数据共享InheritedWidget

Flutter状态管理——InheritedWidget数据共享的原理分析