【问题标题】:Understanding Flutter didChangeDependencies mechanics了解 Flutter didChangeDependencies 机制
【发布时间】:2019-02-12 01:51:19
【问题描述】:

阅读文档hereState 生命周期here 后,我仍然不确定didChangeDependencies 的工作原理。

据我了解,它将在initStateInheritedWidget 发生任何更改之后触发,但这些更改是什么?我认为了解什么更改触发didChangeDependencies 很重要,这样我们才能了解何时以及如何正确使用它。

【问题讨论】:

    标签: flutter


    【解决方案1】:

    didChangeDependencies() 在此 [State] 对象的依赖项发生更改时调用。 那么,究竟它是如何被调用的? 根据上面的定义,看起来它会在状态改变后被调用,但我们是如何知道状态改变的呢? 例子: 下面的示例使用 Provider 状态管理机制从父窗口小部件更新子窗口小部件。 Provider 有一个名为 updateShouldNotify 的属性,它决定是否更改状态。如果它返回 true,那么只会在 ChildWidget 类中调用 didChangeDependencies。 updateShouldNotify 默认在内部返回 true,因为它知道状态已更改。

    为什么我们需要 updateShouldNotify?

    这是必需的,因为如果有人想在特定条件下更新状态。例如:如果 UI 需要仅显示偶数值,那么我们可以添加一个条件,如

    updateShouldNotify: (oldValue, newValue) => newValue % 2 == 0,
    

    代码片段:

    class ParentWidget extends StatefulWidget {
      ParentWidget({Key key, this.title}) : super(key: key);
      final String title;
      @override
      _ParentWidgetState createState() => _ParentWidgetState();
    }
    class _ParentWidgetState extends State<ParentWidget> {
      int _counter = 0;
      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Life Cycle'),
          ),
          body: Provider.value(
            value: _counter,
            updateShouldNotify: (oldValue, newValue) => true,
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    'Press Fab button to increase counter:',
                  ),
                  ChildWidget()
                ],
              ),
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ),
        );
      }
    }
    class ChildWidget extends StatefulWidget {
      @override
      _ChildWidgetState createState() => _ChildWidgetState();
    }
    class _ChildWidgetState extends State<ChildWidget> {
      int _counter = 0;
      @override
      void initState() {
        print('initState(), counter = $_counter');
        super.initState();
      }
      @override
      void didChangeDependencies() {
        _counter = Provider.of<int>(context);
        print('didChangeDependencies(), counter = $_counter');
        super.didChangeDependencies();
      }
      @override
      Widget build(BuildContext context) {
        print('build(), counter = $_counter');
        return Text(
          '$_counter',
        );
      }
    }
    

    输出日志:

    I/flutter ( 3779): didChangeDependencies(), counter = 1
    I/flutter ( 3779): build(), counter = 1
    

    更多信息:

    https://medium.com/@jitsm555/differentiate-between-didchangedependencies-and-initstate-f98a8ae43164

    【讨论】:

    • 对我来说,混淆的主要来源是“依赖”的模糊概念。我在文档中找不到依赖项的正式定义。唯一的提示是这句话:如果之前的 build 调用引用了后来更改的 InheritedWidget。在这方面,我觉得这个例子令人困惑:_ChildWidgetStatebuild 方法没有“引用”任何底层InheritedWidget,是吗?那么,如果对它的唯一“引用”来自didChangeDependencies 本身,Flutter 怎么知道提供者是一个依赖项?
    【解决方案2】:

    TLDR

    作为 Widget 的创建者,您通过使用 ofmaybeOf 等设置它的依赖项(InheritedWidget),因此您应该了解他们何时调用 updateShouldNotify(或者他们是依赖项调用它)。这很复杂:

    用法

    您通常不必在State 中重写此方法,因为无论如何当依赖项发生更改时,您的小部件都会重新构建。如果您想做昂贵的工作,例如发出网络请求,那么您将避免在正常构建中发出该网络请求,而是将这项昂贵的工作放在didChangeDependencies 中。这允许您仅在依赖项更改时进行这些昂贵的操作。 Tbh,如果您将应用程序的逻辑正确地构建到服务中,那么我很难想到如果InheritedWidget 发生更改,那么您只想进行昂贵的操作。于是我查看了 Flutter 框架的内部结构......

    didChangeDependencies 覆盖示例:

    • Flutter 的 Image 小部件(cmets 是我的评论,tbh load 可能不是我使用的正确词,但 resolve 恕我直言也好不到哪里去)
      @override
      void didChangeDependencies() {
        _updateInvertColors(); // Checks if the image should inverted or not.
        _resolveImage(); // Reloads the image if necessary?
    
        if (TickerMode.of(context)) // This method returns a bool: Whether tickers in the given subtree should be enabled or disabled.
          _listenToStream(); // Keep loading the image
        else
          _stopListeningToStream(keepStreamAlive: true); // Be efficient and not read from the stream if not needed. (ticker is false)
    
        super.didChangeDependencies();
      }
    
    • 什么时候调用didChangeDependencies?又名。 Image 的依赖项是什么(都是InheritedWidgets)?它使用both of and maybeOf注册InheritedWidget依赖,包括MediaQueryDirectionalityDefaultAssetBundleTickerModeLocalizations。因此,当这些依赖项更改/更新时,ImagedidChangeDependencies 将被调用

    什么是依赖?

    您使用InheritedWidgetType.of(context) 使一个小部件依赖InheritedWidget 的子类型上,该子类型在内部调用context.dependOnInheritedWidgetOfExactType&lt;InheritedWidgetType&gt;();。所以小部件依赖于InheritedWidget。比如Theme.of(BuildContext context)可以看到here

    来自 Flutter Framework 的 cmets 中关于 dependOnInheritedWidgetOfExactType 的文档:

    获取给定类型T最近的widget,它必须是 具体 [InheritedWidget] 子类的类型,并注册它 使用该 widget 构建上下文,以便当该 widget 更改(或 引入了该类型的新 widget,或者 widget 消失), 这个构建上下文被重建,以便它可以从 那个小部件

    一旦 widget 通过调用注册对特定类型的依赖项 这个方法,它会被重建,并且[State.didChangeDependencies] 每当与该小部件相关的更改发生时都会调用,直到 下次移动小部件或其祖先之一时(对于 例如,因为添加或删除了祖先)。

    more docs, which are really interesting, have a read


    Jitesh's answer 目前是错误的。依赖不是Widget的状态,它们只与InheritedWidget相关。

    【讨论】:

      【解决方案3】:

      当 Flutter 调用 updateShouldNotify() 并返回 true 时,之前在 build() 中请求继承的小部件的小部件会通过被调用的 didChangeDependencies 通知。

      updateShouldNotify 应该返回 true,如果它的状态自上次调用以来发生了变化。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-04-24
        • 2013-12-29
        • 2012-08-06
        • 2018-01-11
        • 2020-08-19
        • 2021-11-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多