InheritedWidget

本文深入探讨Flutter中的状态管理机制,特别是Widget间的状态传递与更新。通过InheritedWidget实现观察者模式,详细解析如何让Widget响应状态变化,保持视图与数据同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Flutter中,对应于Widget之内状态管理,Widget之间的状态是如何管理和以及传递的?
具体例子,对于Text这样的组件,它是如何根据主题配置信息,改变其默认的字体大小,颜色等?

假设存在Widget,A,B,C,依赖关系A<B<C,A中使用StatefullWidget保存一个状态,C需依据A状态变换而变化,那么当A变化时需要重建组件树 B<C,可B并不依赖A的状态,不愿因A状态的变化而重建?解决这个问题,就需要InheritedWidget了。

理解InheritedWidget,可以套用观察者模式,InheritedWidget是一个数据源(被观察者),对应上述A,观察者对应上述C,那么问题就可以理解为这个观察模式如何实现的?可分以下三个问题?

  1. Observer如何持有Observable?即,下层Widget如何获取到InheritedWidget的引用?
  2. 如何订阅?即,事件源添加订阅者。
  3. 事件发生时,事件如何传递?即,InheritedWidget保存状态发生变化时,这个变化如何传递到依赖该状态的Widget。

下层Widget如何获取到InheritedWidget的引用?

我们知道Widget仅是一个组件描述,实际上在我们概念上组件树是由Element组成的,通常一个Widget对应着一个Element,由此我们查看Element源码

// class Element

  Map<Type, InheritedElement> _inheritedWidgets;	
  void mount(){	
      _updateInheritance();
  }
  void _updateInheritance() {	
      _inheritedWidgets = _parent?._inheritedWidgets;
  }

// class InheritedElement

  void _updateInheritance() {
    _inheritedWidgets[widget.runtimeType] = this;
  }

当Element被加载到Element树时,在mount()方法中,获取上层的_inheritedWidgets Map。 而在这个 Map中的数据,在InheritedElement中填充的,Key是InheritedWidget的runtimeType,Value则是InheritedElement本身。这样,每个Widget都可以持有着上层InheiritedWiddget的引用,也可以说观察者持有事件源引用了。

如何订阅?即,事件源添加订阅者。

看事件源的实现类,存在也一个Map _dependents,Key保存着订阅该数据源的观察者Widget,

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

而如何添加添加Widget呢?

  // class BuildContext
  //  Context注册一个InheritedElement,当其变化时,导致BuildContext重建,进而使Contex对应的Widget的重建
  InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect });
 // 其实质是导致
  @protected
  void setDependencies(Element dependent, Object value) {
    _dependents[dependent] = value;
  }

简答说,就是观察者订阅某个数据源时,其本质就是将该观察者添加到上述Map中。

InheritedWidget保存状态发生变化时,这个变化如何传递到依赖该状态的Widget。

当InheritedWidget发生变化时,

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

  // 通知所有的观察者
  void notifyClients(InheritedWidget oldWidget) {
    for (final Element dependent in _dependents.keys) {
      notifyDependent(oldWidget, dependent);
    }
  }
  
	//标记该观察者Widget需要重建,在我们的观察者Widget中,重写该方法针对数据源做出处理
  void didChangeDependencies() {
    markNeedsBuild();
  }

在数据源变化时,会通知所有的观察者,观察者在didChangeDependencies()方法中可以针对信息的数据做出处理,并导致该Widdget的Build再次执行,从而完成页面与数据的同步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值