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

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

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

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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

软件开发本质论

软件开发本质论

Ron Jeffries / 王凌云 / 人民邮电出版社图灵分社 / 2017-1 / 39

想象你正在攀登一座名为“软件开发”的山峰。本书是与你同登一座山峰的敏捷先驱所带来的话语与图片。他在崎岖的山路边找到相当平坦的歇脚处,画下所见的风景,并写下自己的想法和发现。他瞧见很多条上山的路,愿以此书与你分享哪条路容易、哪条路困难、哪条路安全、哪条路危险。他还想指引你欣赏身后的美景。正是这些美景丰富了你的登山之旅,让你在重重困难中收获成长。 “对于每一位CTO、技术VP、软件产品总......一起来看看 《软件开发本质论》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具