Flutter InheritedWidget实现原理
前言
在Flutter开发中,对于一些简单的数据传递,我们可以使用Widget constructor直接传递进去,但是当某个后代Widget依赖上层的祖先Widget或者多个Widget同时依赖祖先Widget的情形时,直接传递的方式就会暴露出很多的问题:需要连续传递很难维护以及依赖的祖先Widget数据改变时,所有子Widget都需要rebuild。
Flutter提供了另外一个机制来解决这个问题,InheritedWidget,当InheritedWidget数据发生变化时,只通知依赖其数据变化的Widgets,接下来将按步骤分析实现细节。( Provider也是基于InheritedWidget进行的封装)
实现细节
我们通过一个小demo来展示使用方法,假设数据Color需要被后代Widget访问,且当Color变化,后代Widget能监听到变化。步骤比较简单,先子类InheritedWidget,如下代码示例,FrogColor定义了一个名为of的静态方法,该方法由后代Widget进行调用,调用时将后代Widget的Element作为context传入。
1 | class FrogColor extends InheritedWidget { |
我们看下of静态方法的实现,实际调用的是后代Widget对应Element的 dependOnInheritedWidgetOfExactType,该方法首先会去_inheritedWidgets里找是否有需要的InheritedWidget,如果找到,返回找到的InheritedWidget,并将自己作为依赖注册到InheritedWidget里,这样InheritedWidget就能知道哪些Widget依赖它,如果InheritedWidget发生了变化,会通知依赖方。_inheritedWidgets会在InheritedWidget mount的时候从父Element获取当前所有的InheritedWidgets,并且把自己也加到里边,也就是说,所有的Element都有一个Map来收集当前祖先所有的InheritedWidget。
1 | @override |
重新回到FrogColor类,另一个方法updateShouldNotify,当FrogColor widget rebuild时,FrogColor的Element会通过updated方法来判断是否需要通知所有依赖它的后代Widgets,super.updated(oldWidget)用来通知所有的dependencies 依赖方。
1 | @override |
当需要通知依赖方的时候,调用依赖Widget对应Element的didChangeDependencies方法,Element将自己标记为dirty,并加到BuildOwner的dirty列表中,当下一帧绘制时,会重新build Widget。
1 | @mustCallSuper |
总结
综上,我们可以看到,InheritedWidget不仅能解决多层传递带来的业务复杂度,也能非常高效的进行rebuild操作。