数据共享-InheritedWidget

InheritedWidget是Flutter中非常重要的一个功能型组件,它提供了一种数据在widget树中从上到下传递、共享的方式,比如我们在应用的根widget中通过InheritedWidget共享了一个数据,那么我们便可以在任意子widget中来获取该共享的数据!这个特性在一些需要在widget树中共享数据的场景中非常方便!如Flutter SDK中正是通过InheritedWidget来共享应用主题(Theme)和Locale (当前语言环境)信息的

didChangeDependencies

在之前介绍StatefulWidget时,我们提到State对象有一个didChangeDependencies回调,它会在“依赖”发生变化时被Flutter Framework调用。而这个“依赖”指的就是子widget是否使用了父widget中InheritedWidget的数据!如果使用了,则代表子widget依赖有依赖InheritedWidget;如果没有使用则代表没有依赖。这种机制可以使子组件在所依赖的InheritedWidget变化时来更新自身!比如当主题、locale(语言)等发生变化时,依赖其的子widget的didChangeDependencies方法将会被调用

如果子widget没有使用了父widget中InheritedWidget的数据!那么不会调用 didChangeDependencies

其实,这个机制很好理解,因为在数据发生变化时只对使用该数据的Widget更新是合理并且性能友好的

上代码:
main

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);



  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {

      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(

        title: Text(widget.title),
      ),
      body: Center(

        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
          ShareDataWidget(
            content: _counter,
            child: ShareChildWidget(),
          ),
//            Text(
//              '$_counter',
//              style: Theme.of(context).textTheme.display1,
//            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

父widget

class ShareDataWidget extends InheritedWidget{

  //共享的数据
  final int content ;
  ShareDataWidget({this.content,Widget child}) : super(child:child);


  // 该回调决定data发生变化时,是否通知子树中依赖data的widget
  @override
  bool updateShouldNotify(ShareDataWidget oldWidget) {
    // TODO: implement updateShouldNotify
    return oldWidget.content != content;
  }



  /*

  定义一个方法,方便子树中的widget获取这个widget,进而获得共享数据

  * */
  static ShareDataWidget of(BuildContext context){

    /**
     * 获取最近的给定类型的Widget,该widget必须是InheritedWidget的子类,
     * 并向该widget注册传入的context,当该widget改变时,
     * 这个context会重新构建以便从该widget获得新的值。
     * 这就是child向InheritedWidget注册的方法。
     */
    return context.inheritFromWidgetOfExactType(ShareDataWidget);
  }
}

子widget

class ShareChildWidget extends StatefulWidget {
  @override
  _ShareChildWidgetState createState() => _ShareChildWidgetState();
}

class _ShareChildWidgetState extends State<ShareChildWidget> {

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Text(ShareDataWidget.of(context).content.toString()),
        //child: Text("123"),
      ),
    );
  }


  /*
  父或祖先widget中InheritedWidget改变(updateShouldNotify 返回true)时
  会被调用

  如果build 中没有依赖 InheritedWidget ,则此回调不会被调用


  * 如果依赖的InheritedWidget改变了,framework将会调用这个方法来通知这个对象。
  * 在这个方法中调用BuildContext.inheritFromWidgetOfExactType是安全的。
  * 子类很少覆写这个方法,因为framework通常会在依赖的InheritedWidget改变后调用build方法,   * 覆写这个方法通常用来做一些耗时的工作,比如网络请求

   */
  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();

    print("didChangeDependencies:");
  }
}

应该在didChangeDependencies()中做什么?

一般来说,子widget很少会重写此方法,因为在依赖改变后framework也都会调用build()方法。但是,如果你需要在依赖改变后执行一些昂贵的操作,比如网络请求,这时最好的方式就是在此方法中执行,这样可以避免每次build()都执行这些昂贵操作

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容