Flutter核心类分析深入理解数据共享Notification
Posted 牧羊人.阿标
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter核心类分析深入理解数据共享Notification相关的知识,希望对你有一定的参考价值。
背景
上一文深入理解InheritedWidget我们知道,InheritedWidget的数据共享方式是父Widget到子Widget的逐层传递,适用于父Widget状态变更通知子widget变更的场景;那么本文讲解的Notification正好相反了,数据的的流动方式就是从子Widget向上传递只父Widget,适用于子widget状态变化,通知上层做相应处理的场景。
Notification用法
Notification用法分为以下几个步骤;
- 自定义一个通知类,需要继承自
Notification
类;
class CustomNotification extends Notification {
CustomNotification(this.msg);
final String msg;
}
- 接收通知的父widget使用
NotificationListener
包装(NotificationListener实际上也是一个StatelessWidget),并实现onNotification
方法
class _MyHomePageState extends State<MyHomePageWidget> {
String _msg = " 通知:\\n";
@override
Widget build(BuildContext context) {
// 监听通知
return NotificationListener<CustomNotification>(
onNotification: (notification) {
setState(() {
_msg += notification.msg;
}); // 收到子 Widget 通知,更新 msg
return false;
},
child: Container(
color: Colors.white,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
_msg,
style: TextStyle(fontSize: 15),
),
CustomChild()
], // 将子 Widget 加入到视图树中
),
),
));
}
}
- 子widget调用
Notification
类的dispatch(context)
方法(父widget的onNotification就会收到通知)。
// 抽离出一个子 Widget 用来发通知
class CustomChild extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton(
// 按钮点击时分发通知
onPressed: () => CustomNotification("Hello\\n").dispatch(context),
child: Text("Send"),
);
}
}
我们来看看效果,点击Button三次:
不出意外,父Widget都能及时收到通知并刷新
下面我们一起通过源码来看看它的原理
原理
上面介绍了Notification的使用方法,现在我们深入其源码来了解一下它的实现原理。我们从通知的源头触发。通知是通过Notification
的dispatch(context)
方法发出的,那我们先看看dispatch(context)方法中做了什么,下面是相关源码:
void dispatch(BuildContext? target) {
target?.visitAncestorElements(visitAncestor);
}
dispatch(context)
中调用了当前context的visitAncestorElements
方法,我们从深入理解BuildContext一文中知道,该方法作用是访问父级Elements。他的参数是一个回调方法。我们这里看看他的源码:
@override
void visitAncestorElements(bool visitor(Element element)) {
assert(_debugCheckStateIsActiveForAncestorLookup());
Element? ancestor = _parent;
while (ancestor != null && visitor(ancestor))
// 遍历父级element
ancestor = ancestor._parent;
}
它会遍历父级element,直到ancestor为null或者某个遍历回调方法返回false。
源码中的参数visitAncestor,就是Notification
类中的visitAncestor
方法。
// 每一个遍历到的父级Element执行此函数
bool visitAncestor(Element element) {
//判断当前element对应的Widget是否是NotificationListener。
//由于NotificationListener是继承自StatelessWidget,
if (element is StatelessElement) {
final StatelessWidget widget = element.widget;
//是NotificationListener,则调用该NotificationListener的_dispatch方法
if (widget is NotificationListener<Notification>) {
if (widget._dispatch(this, element)) // that function checks the type dynamically
return false;
}
}
return true;
}
visitAncestor会判断每一个遍历到的父级Widget是否是NotificationListener,如果不是,那么久返回true,继续遍历,如果是,就调用NotificationListener的_dispatch方法,是否继续遍历同样是根据_dispatch
方法的返回值来判断。
来看看NotificationListener的_dispatch
bool _dispatch(Notification notification, Element element) {
if (onNotification != null && notification is T) {
final bool result = onNotification!(notification);
return result == true; // so that null and false have the same effect
}
return false;
}
我们可以看到,NotificationListener
的onNotification
回调最终是在_dispatch
方法中执行的。是否继续向上遍历同样也是根据onNotification方法的返回值来判断,返回为true继续遍历,返回为false终止遍历。
到了这里整个Notification的流程就形成 了一个闭环。
总结一下
我们其实发现Notification的源码其实很简单,没什么复杂的逻辑。Notification的核心功能也就是实现了子Widget向父Widget传递消息。看源码同样也是支持多个NotificationListener嵌套通知实现。
Flutter中也有很多类似的场景比如,ScrollNotification
,LayoutChangedNotification
等等。。。。。。
以上是关于Flutter核心类分析深入理解数据共享Notification的主要内容,如果未能解决你的问题,请参考以下文章
Flutter核心类分析深入理解数据共享Notification