【问题标题】:How does the Widget Lifecycle work in Flutter?Flutter 中的 Widget 生命周期是如何工作的?
【发布时间】:2021-07-24 11:33:01
【问题描述】:

要优化 Flutter App 的性能,重要的是仅在实际需要重建 Widget 时才重建它们。在使用const WidgetsTransitionBuilder patternKeysoverwritten the == operator 之间似乎有不同的方法来减少 Widget 重建,但我不知道如何交互。

官方文档建议在构建方法中做尽可能少的工作。这与在 Widget 的构造函数中完成的工作相比如何?构造函数的调用频率是否与构建函数一样频繁,多于还是少于它?如果我有 Stateful Widget,是否可以通过在 state 中而不是在构造函数或 build 方法中缓存一些数据来提高性能?

在 Reddit 上有一个关于使用 functions vs. Stateless Widgets 的讨论,其中一些人认为无状态小部件会导致更少的重建,而另一些人则认为没有区别。我想充分了解 Flutter 的 Widget Lifecycle,以了解在特定情况下两者之间是否存在差异。

我正在寻找有关这些不同机制如何交互的解释,以便就如何减少我的应用中不必要的 Widget 构建做出正确的决定。

【问题讨论】:

    标签: flutter flutter-widget


    【解决方案1】:

    并非每次重建都像您想象的那样昂贵

    这个问题在过去困扰了我很多 :) 直到你意识到小部件并不是全部。这只是冰山一角! .对于每个小部件对象,实际上还有另外两个与之关联的对象首先是 element 另一个称为 render 您可以将小部件视为只是在小部件销毁然后创建时的配置对象本身并不昂贵,但昂贵的是渲染对象的创建,幸运的是渲染对象不会在每次构建时重新构建,直到需要它,所以它以一种非常有效和智能的方式与新的小部件进行比较和重新关联,即为什么颤振开箱即用的性能如此之好。 希望对您有所帮助,如果需要,我将非常乐意澄清更多信息。

    【讨论】:

    • 我的问题是关于“高效和智能方式”的工作原理。说“它很聪明”并不能回答问题。
    • @Christian 没什么特别的,它的算法是比较新小部件的新配置,并在需要时使用 skia 渲染器相应地更新渲染
    • 说它不特别并不能告诉我关于重新渲染什么的决定是如何做出的。
    • @Christian 我说它很聪明。没什么特别的,毕竟它是另一种算法,如果您需要了解更多信息,可以在这里查看flutter.dev/docs/resources/inside-flutter,希望对您有所帮助
    【解决方案2】:

    我宁愿从开发者自己那里得到一个很好的解释,here is a short clip explaining the widget lifecycle

    2019 At Google Developer Days China做了更详细的解释

    如果您谈论性能,那么函数式方法会更好。 考虑一下:

    class TestWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        final streamController = StreamController<String>.broadcast();
    
        Future.delayed(Duration(seconds: 3)).then((_) {
          streamController.sink.add('new value to received');
    
          streamController.close();
        });
    
        return StreamBuilder(
          stream: streamController.stream,
          builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
            final newVal = snapshot.data;
            return Text(newVal ?? 'this is initial value');
          },
        );
      }
    }
    

    在函数式方法中,状态不是由小部件而是由streamController 保持,TestWidget 的构建方法只调用一次,并且每次有新的时调用builderstream 内的事件。

    我发现这种方法开发起来也是最灵活的,因为您可以在一个地方拥有多个流,并且作为木偶操作者来控制它们。

    ==== 一个小切线 ========================================= ==============

    我建议你研究一下BLoC 模式。

    根据我的经验,如果你狂热地遵循一种方法而不是另一种方法,你最终可能会“伤害自己”,所以我建议不要害怕同时使用这两种方法,具体取决于用例。

    例如,如果您有一个按钮,其内部具有递增的 int 值(如徽章),并且当您点击时它会递增。将值发送到 BLoC 并将其保存在那里,然后通过流发送回事件以更新 UI 是矫枉过正的,这是我将使用 StatefulWidget 的地方。

    【讨论】:

    • 我确实使用 Bloc。那没有回答问题。第一个链接的视频基本上说“Flutter 在后台做智能魔术”。我的问题是关于理解魔法。
    • 在第二个剪辑中解释了更多关于你所谈论的魔法。
    • 简而言之:无论您使用哪种方法来更改状态,从性能的角度来看,更新WidgetElementRenderObject 树的过程都是相同的。对于上面的示例,我想说的是,使用builder,您将在重建期间实例化更少的对象以更新Text
    • 我的问题是关于我列出的所有因素如何影响性能。我在您的回答中没有看到任何东西告诉我 const 和覆盖 == 如何影响性能,因此它并没有真正告诉我我目前不知道的任何问题。
    • I would like to understand Flutter's Widget Lifecycle well enough to understand whether in a particular case there's a difference between the two or there isn't.这不是你感兴趣的问题吗?
    猜你喜欢
    • 2023-03-07
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-18
    相关资源
    最近更新 更多