Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

栏目: IOS · Android · 发布时间: 6年前

内容简介:可以说是目前 全网 最完整的返回给定类型的最近父

demo 地址: github.com/LZQL/flutte…

可以说是目前 全网 最完整的 demo 演示了

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

2. ancestorWidgetOfExactType

返回给定类型的最近父 widget ,该 widget 的类型必须是具体 widget 的子类。

一般来说, inheritFromWidgetOfExactType 更有用,因为继承的 widget 将在更改时触发消费者重新构建。 ancestorWidgetOfExactType 适用于交互事件处理程序(例如手势回调)或执行一次性任务,例如 断言 您拥有或不具有作为特定类型的父 widgetwidget 的构建方法的返回值不应该依赖于该方法返回的值,因为如果该方法的返回值发生更改,构建上下文将 不会重新生成 。这可能会导致生成方法中使用的数据发生更改,但是没有重新生成 widget

总结一下上面的意思:

  1. ancestorWidgetOfExactType 一般用于 断言,是否有特定类型的父 widget
  2. ancestorWidgetOfExactType 可以用来获取父 widget 的一些信息
  3. 如果想要根据方法的返回值来判断是否重新构建, ancestorWidgetOfExactType 并不适用

下面会分别给出 上面的 3 点总结来给出 demo 场景

1. 断言

这边就不给出自己的 demo ,直接看源码,源码的应用场景说明一切,这边也是官方翻译的最好证明

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget
从上图可以看出,这是 Hero

的源码,做了断言,断言就写到这里

2. 获取父 widget 的一些信息

1. 代码结构

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

2. 运行效果

WidgeC 是一个 加号按钮, 点击了 WidgeC ,获取 HomepageState 调用 incrementCounter 方法, , widgetAwidgetBwidgetC 会重新 build ,看下图

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

3. 具体代码

代码位置 ancestor01.dart

/// ancestorWidgetOfExactType 获取父widget的一些信息
class MyAncestorTree01 extends StatefulWidget {
  @override
  _MyAncestorTree01State createState() => _MyAncestorTree01State();
}

class _MyAncestorTree01State extends State<MyAncestorTree01> {
  @override
  Widget build(BuildContext context) {
    return TopPage01();
  }
}

class TopPage01 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Demo'),
        ),
        body: HomePage(),
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  final HomePageState state = HomePageState();

  @override
  HomePageState createState() {
    return state;
  }
}

class HomePageState extends State<HomePage> {
  int counter = 0;

  void incrementCounter() {

    setState(() {
      counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          WidgetA(),
          WidgetB(),
          WidgetC(),
        ],
      ),
    );
  }
}

class WidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    /// 获取 HomePageState 来获取 counter
    final HomePage widget =
        context.ancestorWidgetOfExactType(HomePage);
    final HomePageState state = widget?.state;

    return Center(
      child: Text(
        '${state == null ? 0 : state.counter}',
        style: Theme.of(context).textTheme.display1,
      ),
    );
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text('Widget  B  Text');
  }
}

class WidgetC extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    /// 获取 HomePageState 来 调用 加法操作
    final HomePage widget = context.ancestorWidgetOfExactType(HomePage);
    final HomePageState state = widget?.state;

    return RaisedButton(
      onPressed: () {
        state?.incrementCounter();
      },
      child: Icon(Icons.add),
    );
  }
}
复制代码

3. 子widget无法检测到父widget的更改

demo 用来演示 子widget无法检测到父widget的更改 的具体情况 为后面的内容做铺垫 我将 ancestorWidgetOfExactType 封装了一个 of 方法放到了 TopPage02 里面, 与 2. 获取父widget 的一些信息 的使用场景不同。

1. 代码结构

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

2. 运行效果

注意看下图,当我点击了 1 - AncestorWidgetOfExactType02 演示 按钮,进入 demo 页面,从右侧可以看出,因为是第一次进去,所以全部 widget 都进行了 build 操作,但是当我 点击 了 Add item 按钮, TopPage02rebuild 但是 WidgetAWidgetBWidgetC ,并不会进行 rebuild

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

3. 具体代码

代码位置 ancestor02.dart

/// ancestorWidgetOfExactType
/// 子widget无法检测到父widget的更改
/// (父widget rebuild 子widget no rebuild)
class MyAncestorTree02 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new TopPage02(
      child: new Scaffold(
        appBar: new AppBar(
          title: new Text('Title'),
        ),
        body: new Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            new WidgetA(),
            new WidgetB(),
            new WidgetC(),
          ],
        ),
      ),
    );
  }
}

class Item {
  String reference;

  Item(this.reference);
}

class TopPage02 extends StatefulWidget {
  TopPage02({
    Key key,
    this.child,
  }) : super(key: key);

  final Widget child;

  final TopPage02State state = new TopPage02State();

  @override
  TopPage02State createState() {
    return state;
  }

  static TopPage02State of(BuildContext context) {
    /// 通过从 TopPage02 的 context 得到树结构来返回第一个 TopPage02State
    return (context.ancestorWidgetOfExactType(TopPage02)
            as TopPage02)
        .state;

  }
}

class TopPage02State extends State<TopPage02> {

  List<Item> _items = <Item>[];

  int get itemsCount => _items.length;

  void addItem(String reference) {
    setState(() {
      _items.add(new Item(reference));
    });
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

class WidgetA extends StatefulWidget {
  @override
  _WidgetAState createState() => _WidgetAState();
}

class _WidgetAState extends State<WidgetA> {
  @override
  Widget build(BuildContext context) {
    final TopPage02State state = TopPage02.of(context);
    return new Center(
      child: new RaisedButton(
        child: new Text('WidgetA :Add Item'),
        onPressed: () {
          /// 这边调用 addItem 方法,但是WidgetA,WidgetB,WidgetC
          /// 并不会 build
          /// 这就说明了:widget的构建方法的返回值不应该依赖于该方法返回的值,
          /// 因为如果该方法的返回值发生更改,构建上下文将不会重新生成。
          /// 这可能会导致生成方法中使用的数据发生更改,但是没有重新生成widget
          state.addItem('new item');
        },
      ),
    );
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final TopPage02State state = TopPage02.of(context);
    return new Text('widgetB itemCount:${state.itemsCount}');
  }
}

class WidgetC extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Text('I am Widget C');
  }
}
复制代码

3. InheritedWidget

1. 什么是 InheritedWidget

特性:

  1. InheritedWidget 是一个可以在树中 高效地向下传递数据 的组件:我们可以在以 InheritedWidget 为节点的树下任一 Widget 中调用 BuildContext.inheritFromWidgetOfExactType 来获取离其最近的 InheritedWidget 实例
  2. 当以上面这种方式(调用 inheritFromWidgetOfExactType 方法时)被引用后,每当 InheritedWidget 自身的状态改变时,会导致 “consumer” (调用 inheritFromWidgetOfExactType 方法的这个 Child ) 重新 build

第一点:在 Flutter 中,正是通过 InheritedWidget 来共享应用主题( Theme )和 Locale (当前语言环境)信息的 第二点:解决了 上面提到 ancestorWidgetOfExactType 的第三点不能通过返回值来进行重新 build 的情况

InheritedWidget 的在 Widget 树中数据传递方向是从上到下的,这和 Notification 的传递方向正好相反。(后面系列文章介绍 Notification )

2. didChangeDependencies

StatefulWidgetState 对象有一个回调 didChangeDependencies ,它会在“依赖”发生变化时被 Flutter Framework 调用。而这个“依赖”指的就是是否使用了父 widgetInheritedWidget 的数据,如果使用了,则代表有依赖,如果没有使用则代表没有依赖。这种机制可以使子组件在所依赖的主题、 locale 等发生变化时有机会来做一些事情。

4. 通过 2 - InheritedWidget演示01 ,发现问题

这个例子 是参照 book.flutterchina.club/chapter7/in… 写的一样,相信很多人都看过

1. 代码结构

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

2. 效果图

当我点击了 click me 按钮 加1, widgetAwidgeB , RaisedButton 会重新 build

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

3. 代码

代码位置: inheritedwidget01.dart

/// InheritedWidget01 , 会导致 `widgetA`,` widgeB`,`RaisedButton `会重新`build`
  class InheritedWidgetTest01 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return InheritedWidgetTest01State();
  }
}

class InheritedWidgetTest01State extends State<InheritedWidgetTest01> {
  int tmpData = 0;

  @override
  Widget build(BuildContext context) {
    print('InheritedWidgetTest01 build');
    return Scaffold(
      body: Center(
        child: ShareInherited(
          data: tmpData,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              WidgetA(),
              WidgetB(),
              RaisedButton(
                child: Text("Click me"),
                onPressed: () {
                  setState(() {
                    print('onPressed');
                    tmpData += 1;
                  });
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class ShareInherited extends InheritedWidget {
  final int data; //需要在子树中共享的数据,保存点击次数

  ShareInherited({@required this.data, @required Widget child}) : super(child: child) {
    print('ShareInherited construct');
  }

  /// 允许所有子 widget 通过包含的 context 获得最近的 ShareInherited 实例
  /// 定义一个便捷方法,方便子树中的widget获取共享数据
  /// 在内部,除了简单地返回 ShareInherited 实例外,它还订阅消费者 widget 以便用于通知更改
  static ShareInherited of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(ShareInherited);
  }

  /// 用来告诉 InheritedWidget 如果对数据进行了修改,
  /// 是否必须将通知传递给所有子 widget(已注册/已订阅)
  @override
  bool updateShouldNotify(ShareInherited oldWidget) {
    // 如果返回true,则子树中依赖(build函数中有调用)本widget
    // 的子widget的`state.didChangeDependencies`会被调用
    bool result = oldWidget.data != this.data;
    print('ShareInherited updateShouldNotify result = $result');
    return result;
  }
}

class WidgetA extends StatefulWidget {
  @override
  _WidgetAState createState() => _WidgetAState();
}

class _WidgetAState extends State<WidgetA> {
  @override
  Widget build(BuildContext context) {
    print('WidgetA build');
    int data = ShareInherited.of(context).data;
    return Text('WidgetA data = $data');
  }

  @override
  void didChangeDependencies() {
    print('WidgetA didChangeDependencies');
    super.didChangeDependencies();
  }
}

class WidgetB extends StatefulWidget {
  @override
  _WidgetBState createState() => _WidgetBState();
}

class _WidgetBState extends State<WidgetB> {
  @override
  Widget build(BuildContext context) {
    print('WidgetB build');
    return Text('WidgetB');
  }

  @override
  void didChangeDependencies() {
    print('WidgetB didChangeDependencies');
    super.didChangeDependencies();
  }
}
复制代码

4. 发现的现象

WidgetA 调用了 inheritFromWidgetOfExactType 方法,获得了存放在 ShareInherited 对象里的 data 数据并显示在 WidgetA 内容上,同时使得 WidgetAShareInherited 产生关联;

当点击 RaisedButton 触发 InheritedWidgetTest01 状态更新时, InheritedWidgetTest01Statebuild 方法回调,重新构建 ShareInherited 对象传入新值,由于 data 发生变化, ShareInherited 的方法 updateShouldNotify 中返回了 true ,最终使得与 ShareInherited 关联的 WidgetA 触发 reBuild

当我们运行并点击 RaisedButton 后,页面表现得确实如上述所示, WidgetA 的内容由 WidgetA data = 0 变为了 WidgetA data = 1 ,似乎 InheritedWidget 正确的使用方式正是如此,但是 log 里输出的却是如下:

I/flutter (11303): onPressed
I/flutter (11303): InheritedWidgetTest01 build
I/flutter (11303): ShareInherited construct
I/flutter (11303): ShareInherited updateShouldNotify result = true
I/flutter (11303): WidgetA didChangeDependencies
I/flutter (11303): WidgetA build
I/flutter (11303): WidgetB build
复制代码

可以看到,结合前面的代码逻辑分析,理论上只有 WidgetA 才会 reBuild ,而现在却产生了 I/flutter (11303): WidgetB build 这条记录。这是为什么呢?

5. 原因分析

其实可以从前面提到的 特性2 找到答案。其中说到: InheriteWidget 状态发生变化时会 rebuild 相关的 child 。 我们知道, flutterWidget 被标识为了 @immutable ,即是不可变的,那么所谓的状态发生变化就意味着 InheriteWidget 重新构建,由于前面代码中在 InheriteWidget 构造时同时也构造的其 child 对象,因此当 InheriteWidget 重新构建时也会导致 child 跟着重新构建,这样也就失去了 “rebuild相关的child” 的意义,

也就是说,要想特性2生效,需要保证 InheriteWidget 节点下的树不会被重新构建。

5. 解决方法1:使用 const Widget

InheriteWidgetchild 转化为 const ,这样即使在重建 InheriteWidget 时,由于其 child 得到的是同一个对象,也就不会导致这个子树重建,选择性 reBuild 也就得到了保证。但是由于 const 特性,相关的参数也必须是常量,因此需要重写或修改的代码量相对较多,因此更推荐 解决方法2 的做法,这个方法在后面回写

1. const demo 01,发现问题

1. 代码结构

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

2. 效果图

WidgeAWidgeBFlatButton 是处于同一级别的

从下图可以看到 当我点击了 click mewidgetB 并不会被 rebuild , 但是 WidgeAFlatButtonrebuild ,这样解决了 WidgeB rebuild 的问题,但是 FlateButton 并不涉及到 页面的数据刷新,如果我想要让 FlatButton 也不 rebuild 呢? 看 constdemo02

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

3. 代码

代码位置: inheritedwidget_const_01.dart

/// 使用 const
/// Widget A ,FlatButton rebuild, Widget B  no rebuild
class InheritedWidgetConst01 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return InheritedWidgetConst01State();
  }
}

class InheritedWidgetConst01State extends State<InheritedWidgetConst01> {
  int tmpData = 0;



  @override
  Widget build(BuildContext context) {
    print('InheritedWidgetTest02 build');
    return Scaffold(
      body: Center(
        child: ShareInherited(
          data: tmpData,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const WidgetA(),
              const WidgetB(),
              FlatButton(
                child: Text("Click me"),
                onPressed: () {
                  setState(() {
                    print('onPressed');
                    tmpData += 1;
                  });
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class ShareInherited extends InheritedWidget {
  final int data;

  ShareInherited({this.data, @required Widget child}) : super(child: child) {
    print('ShareInherited construct');
  }

  @override
  bool updateShouldNotify(ShareInherited oldWidget) {
    bool result = oldWidget.data != this.data;
    print('ShareInherited updateShouldNotify result = $result');
    return result;
  }

  static ShareInherited of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(ShareInherited);
  }
}

class WidgetA extends StatelessWidget {

  const WidgetA();

  @override
  Widget build(BuildContext context) {
    print('WidgetA build');
    int data = ShareInherited.of(context).data;
    return Text('WidgetA data = $data');
  }
}

class WidgetB extends StatelessWidget {

  const WidgetB();

  @override
  Widget build(BuildContext context) {
    print('WidgetB build');
    return Text('WidgetB');
  }
}
复制代码

2. const demo 02,继续发现问题

1. 代码结构

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

2. 效果图

你会发现, WidgeAWidgeC 还是 rebuild , 要解决这个问题,就需要用到 文章顶部提到的 ancestorWidgetOfExactType 了,看 const demo 03,终极写法

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

3. 代码

代码位置 inheritedwidget_const_02.dart

/// 使用 const
/// Widget A ,Widget C  rebuild, Widget B  no rebuild
class InheritedWidgetConst02 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return InheritedWidgetConst02State();
  }
}

class InheritedWidgetConst02State extends State<InheritedWidgetConst02> {
  int tmpData = 0;

  void addItem(){
    setState(() {
      tmpData++;
    });
  }

  @override
  Widget build(BuildContext context) {
    print('InheritedWidgetTest02 build');
    return Scaffold(
      body: Center(
        child: ShareInherited(
          data: tmpData,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const WidgetA(),
              const WidgetB(),
              WidgetC(),
            ],
          ),
          state: this,
        ),
      ),
    );
  }
}

class ShareInherited extends InheritedWidget {
  final int data;
  final InheritedWidgetConst02State state;
  ShareInherited({this.data, @required Widget child,this.state}) : super(child: child) {
    print('ShareInherited construct');
  }

  @override
  bool updateShouldNotify(ShareInherited oldWidget) {
    bool result = oldWidget.data != this.data;
    print('ShareInherited updateShouldNotify result = $result');
    return result;
  }

  static ShareInherited of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(ShareInherited);
  }
}

class WidgetA extends StatelessWidget {

  const WidgetA();

  @override
  Widget build(BuildContext context) {
    print('WidgetA build');
    int data = ShareInherited.of(context).data;
    return Text('WidgetA data = $data');
  }
}

class WidgetB extends StatelessWidget {

  const WidgetB();

  @override
  Widget build(BuildContext context) {
    print('WidgetB build');
    return Text('WidgetB');
  }
}



class WidgetC extends StatefulWidget {
  @override
  _WidgetCState createState() => _WidgetCState();
}

class _WidgetCState extends State<WidgetC> {
  @override
  Widget build(BuildContext context) {
    print('Widge C build');
    InheritedWidgetConst02State state = ShareInherited.of(context).state;

    return FlatButton(
      child: Text("Click me"),
      onPressed: () {
        setState(() {
          print('onPressed');
          state.addItem();
        });
      },
    );
  }
}
复制代码

3. const demo 03,终极写法

1. 代码结构

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

2. 效果图

ShareInheritedof 方法 ,增加了 是否 rebuild 的参数 你会发现 ,现在只有 WidgeArebuild ,完美啊

static ShareInherited of([BuildContext context, bool rebuild = true]) {
    return (rebuild
        ? context.inheritFromWidgetOfExactType(ShareInherited)
        : context.ancestorWidgetOfExactType(ShareInherited) );
  }
复制代码
Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

3. 代码

代码位置 inheritedwidget_const_03.dart

/// 使用 const
/// Widget A rebuild, Widget B Widget C no rebuild
class InheritedWidgetConst03 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return InheritedWidgetConst03State();
  }
}

class InheritedWidgetConst03State extends State<InheritedWidgetConst03> {
  int tmpData = 0;

  void addItem() {
    setState(() {
      tmpData++;
    });
  }

  @override
  Widget build(BuildContext context) {
    print('InheritedWidgetTest02 build');
    return Scaffold(
      body: Center(
        child: ShareInherited(
          data: tmpData,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const WidgetA(),
              const WidgetB(),
              const WidgetC(),
            ],
          ),
          state: this,
        ),
      ),
    );
  }
}

class ShareInherited extends InheritedWidget {
  final int data;
  final InheritedWidgetConst03State state;

  ShareInherited({this.data, @required Widget child, this.state})
      : super(child: child) {
    print('ShareInherited construct');
  }

  @override
  bool updateShouldNotify(ShareInherited oldWidget) {
    bool result = oldWidget.data != this.data;
    print('ShareInherited updateShouldNotify result = $result');
    return result;
  }

  static ShareInherited of([BuildContext context, bool rebuild = true]) {
    return (rebuild
        ? context.inheritFromWidgetOfExactType(ShareInherited)
        : context.ancestorWidgetOfExactType(ShareInherited) );
  }
}

class WidgetA extends StatelessWidget {

  const WidgetA();

  @override
  Widget build(BuildContext context) {
    print('WidgetA build');
    int data = ShareInherited
        .of(context)
        .data;
    return Text('WidgetA data = $data');
  }
}

class WidgetB extends StatelessWidget {

  const WidgetB();

  @override
  Widget build(BuildContext context) {
    print('WidgetB build');
    return Text('WidgetB');
  }
}

class WidgetC extends StatelessWidget {
  const WidgetC();
  @override
  Widget build(BuildContext context) {
    print('Widge C build');
    InheritedWidgetConst03State state = ShareInherited.of(context,false).state;

    return FlatButton(
      child: Text("Click me"),
      onPressed: () {
        print('onPressed');
        state.addItem();
      },
    );
  }
}
复制代码

6. 解决方法2:上移 Child 对象到 InheriteWidgetParent Widget

1. out demo 01,发现问题

1. 代码结构

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

2. 效果图

具体看代码吧,稍显复杂 ,这边命名不是很规范,懒得改了, 太累了写 demo ,看代码可以知道

class ShareInherited extends StatelessWidget
复制代码

这里的 ShareInherited 是一个 StatelessWidget ,也就是 上移了 Child 对象到 InheriteWidgetParent Widget

class _ShareInherited extends InheritedWidget
复制代码

_ShareInherited 才是 具体的 InheritedWidget

看下图可知 Widget A ,FlatButton rebuild, Widget B no rebuild

这时候我们 一样的 把 FlatButton 放到 WidgetC 然后上移到 InheriteWidgetParent Widget 看能不能实现让 WidgeC no rebuild

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

3. 代码

代码位置 inheritedwidget_out_01.dart

/// 上移`Child`对象到`InheriteWidget`的`Parent Widget`
/// Widget A ,FlatButton rebuild, Widget B  no rebuild
class InheritedWidgetOut01 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return InheritedWidgetOut01State();
  }
}

class InheritedWidgetOut01State extends State<InheritedWidgetOut01> {
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: MyWidget(
          Column(
            children: <Widget>[
              WidgetA(),
              WidgetB()
            ],
          )
      ),
    );
  }
}

class MyWidget extends StatefulWidget {

  final Widget child;
  MyWidget(this.child);

  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {

  int tempData = 0;

  @override
  Widget build(BuildContext context) {
    return ShareInherited(
      data: tempData,
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            widget.child,
            FlatButton(
                  child: Text("Click me"),
                  onPressed: () {
                    setState(() {
                      print('onPressed');
                      tempData += 1;
                    });
                  },
                )
          ],
        ),
      ),
    );
  }
}

class ShareInherited extends StatelessWidget {
  final int data;
  final Widget child;


  ShareInherited({
    Key key,
    this.data,
    this.child
  }): assert(child != null),
        assert(data != null),
        super(key: key);

  static int of(BuildContext context) {
    final _ShareInherited inheritedTheme = context.inheritFromWidgetOfExactType(_ShareInherited);
    return inheritedTheme.shareInherited.data;
  }

  @override
  Widget build(BuildContext context) {
    return _ShareInherited(shareInherited:this , child: child,);
  }
}

class _ShareInherited extends InheritedWidget{

  final ShareInherited shareInherited;

  _ShareInherited({
    Key key,
    @required this.shareInherited,
    @required Widget child,
  }):assert(shareInherited != null),
  super(key: key, child: child);

  @override
  bool updateShouldNotify(_ShareInherited oldWidget) {
    return shareInherited.data != oldWidget.shareInherited.data;
  }

}

class WidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('WidgetA build');
    int data = ShareInherited.of(context);
    return Text('WidgetA data = $data');
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('WidgetB build');
    return Text('WidgetB');
  }
}
复制代码

2. out demo 02,继续发现问题

1. 代码结构

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

2. 效果图

你会发现 Widget A ,Widget C rebuild, Widget B no rebuild

如果想要 让 Widge C no rebuild,看 out demo 03

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

3. 代码

代码位置 inheritedwidget_out_02.dart

/// 上移`Child`对象到`InheriteWidget`的`Parent Widget`
/// Widget A ,Widget C  rebuild, Widget B  no rebuild
class InheritedWidgetOut02 extends StatefulWidget {
  @override
  _InheritedWidgetOut02State createState() => new _InheritedWidgetOut02State();
}

class _InheritedWidgetOut02State extends State<InheritedWidgetOut02> {
  @override
  Widget build(BuildContext context) {
    return new MyInheritedWidget(
      child: new Scaffold(
        appBar: new AppBar(
          title: new Text('Title'),
        ),
        body: Center(
          child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[new WidgetA(), new WidgetB(), new WidgetC()],
          ),
        ),
      ),
    );
  }
}

class MyInheritedWidget extends StatefulWidget {
  MyInheritedWidget({
    Key key,
    this.child,
  }) : super(key: key);

  final Widget child;

  @override
  MyInheritedWidgetState createState() => new MyInheritedWidgetState();

  static MyInheritedWidgetState of([BuildContext context]) {
    return (context.inheritFromWidgetOfExactType(_MyInherited) as _MyInherited).data;
    // 通过从 MyInheritedWidget 的 context 得到树结构来返回第一个 MyInheritedWidgetState
  }
}

class MyInheritedWidgetState extends State<MyInheritedWidget> {

  int tempData = 0;

  /// Helper method to add an Item
  void addItem() {
    setState(() {
      tempData++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new _MyInherited(
      data: this,
      child: widget.child,
    );
  }
}

class _MyInherited extends InheritedWidget {
  _MyInherited({
    Key key,
    @required Widget child,
    @required this.data,
  }) : super(key: key, child: child);

  final MyInheritedWidgetState data;

  @override
  bool updateShouldNotify(_MyInherited oldWidget) {
    return true;
  }
}

class WidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('Widget A build');
    final MyInheritedWidgetState state = MyInheritedWidget.of(context);
    return Text('WidgetA data = ${state.tempData}');
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('Widget B build');
    return Text('WidgetB');
  }
}

class WidgetC extends StatefulWidget {
  @override
  _WidgetCState createState() => _WidgetCState();
}

class _WidgetCState extends State<WidgetC> {
  @override
  Widget build(BuildContext context) {
    print('Widget C build');
    final MyInheritedWidgetState state = MyInheritedWidget.of(context);
    return RaisedButton(
      child: Text("Click me"),
      onPressed: () {
        print('onPressed');
        state.addItem();
      },
    );
  }
}
复制代码

3. out demo 03,终极写法

1. 代码结构

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

2. 效果图

因为这个 demoPerfomance 界面展示不够形象,就直接展示输出 log 查看结果比较形象

可以发现 Widget A rebuild, Widget B Widget C no rebuild ,完美啊 ,写到这里已经要吐了

Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget

3. 代码

代码位置 inheritedwidget_out_03.dart

/// 上移`Child`对象到`InheriteWidget`的`Parent Widget`
/// Widget A rebuild, Widget B Widget C no rebuild
class InheritedWidgetOut03 extends StatefulWidget {
  @override
  _InheritedWidgetOut03State createState() => new _InheritedWidgetOut03State();
}

class _InheritedWidgetOut03State extends State<InheritedWidgetOut03> {
  @override
  Widget build(BuildContext context) {
    return new MyInheritedWidget(
      child: new Scaffold(
        appBar: new AppBar(
          title: new Text('Title'),
        ),
        body: Center(
          child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[new WidgetA(), new WidgetB(), new WidgetC()],
          ),
        ),
      ),
    );
  }
}

class MyInheritedWidget extends StatefulWidget {
  MyInheritedWidget({
    Key key,
    this.child,
  }) : super(key: key);

  final Widget child;

  @override
  MyInheritedWidgetState createState() => new MyInheritedWidgetState();

  static MyInheritedWidgetState of(
      [BuildContext context, bool rebuild = true]) {
    return (rebuild
            ? context.inheritFromWidgetOfExactType(_MyInherited) as _MyInherited
            : context.ancestorWidgetOfExactType(_MyInherited) as _MyInherited)
        .data;
    // 通过从 MyInheritedWidget 的 context 得到树结构来返回第一个 MyInheritedWidgetState
  }
}

class MyInheritedWidgetState extends State<MyInheritedWidget> {

  int tempData = 0;

  /// Helper method to add an Item
  void addItem() {
    setState(() {
      tempData++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new _MyInherited(
      data: this,
      child: widget.child,
    );
  }
}

class _MyInherited extends InheritedWidget {
  _MyInherited({
    Key key,
    @required Widget child,
    @required this.data,
  }) : super(key: key, child: child);

  final MyInheritedWidgetState data;

  @override
  bool updateShouldNotify(_MyInherited oldWidget) {
    return true;
  }
}

class WidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('Widget A build');
    final MyInheritedWidgetState state = MyInheritedWidget.of(context);
    return Text('WidgetA data = ${state.tempData}');
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('Widget B build');
    return Text('WidgetB');
  }
}

class WidgetC extends StatefulWidget {
  @override
  _WidgetCState createState() => _WidgetCState();
}

class _WidgetCState extends State<WidgetC> {
  @override
  Widget build(BuildContext context) {
    print('Widget C build');
    final MyInheritedWidgetState state = MyInheritedWidget.of(context, false);
    return RaisedButton(
      child: Text("Click me"),
      onPressed: () {
        print('onPressed');
        state.addItem();
      },
    );
  }
}
复制代码

7. 两种解决方法,在源码中的应用

方法1 : 可以查看 TickerMode 这个类

方法2: 可以查看 Theme


以上所述就是小编给大家介绍的《Flutter - 数据共享,通信,状态管理 - 01 - InheritedWidget》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Probabilistic Method

The Probabilistic Method

Noga Alon、Joel H. Spencer / Wiley-Interscience / 2008-8-11 / USD 137.00

Praise for the Second Edition : "Serious researchers in combinatorics or algorithm design will wish to read the book in its entirety...the book may also be enjoyed on a lighter level since the diffe......一起来看看 《The Probabilistic Method》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具