小部件函数和类之间的性能差异

3 performance rebuild widget flutter

在这种情况下,关于重建小部件和性能方面,两个选项之间有什么区别?

\n

小部件类:

\n
class Dummy() extends StatelessWidget {\n  const Dummy();\n\n  @override\n  Widget build(BuildContext context) {\n    return const Text(\xe2\x80\x9etext\xe2\x80\x9c);\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

选项1:

\n
class Option1 extends StatelessWidget {\n  const Option1();\n\n  @override\n  Widget build(BuildContext context) {\n    return SizedBox(\n      child: const Dummy(),\n    );\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

选项2:

\n
class Option2 extends StatelessWidget {\n  const Option2();\n\n  Widget createDummyWidget() {\n    return const Dummy();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return SizedBox(\n      child: createDummyWidget(),\n    );\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

小智 5

将小部件拆分为方法是一种反模式

\n

因此,举例来说,如果我们有一个看起来像这样的小部件:

\n
class _MyStatefulWidgetState extends State<MyStatefulWidget> {\n  int _counter = 0;\n\n  @override\n  Widget build(BuildContext context) {\n    return Row(\n      children: [\n        Text(\'Counter: $_counter\'),\n        Container(\n          child: Column(\n            children: [\n              Text(\'Hello\'),\n              Row(\n                children: [\n                  Text(\'there\'),\n                  Text(\'world!\'),\n                ],\n              ),\n            ],\n          ),\n        ),\n      ],\n    );\n  }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

如果使用函数小部件

\n
class _MyStatefulWidgetState extends State<MyStatefulWidget> {\n  int _counter = 0;\n\n  Widget _buildNonsenseWidget() {\n    return Container(\n      child: Column(\n        children: [\n          Text(\'Hello\'),\n          Row(\n            children: [\n              Text(\'there\'),\n              Text(\'world!\'),\n            ],\n          ),\n        ],\n      ),\n    );\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Row(\n      children: [\n        Text(\'Counter: $_counter\'),\n\n        // The deeply nesting widget is now refactored into a\n        // separate method and we have a cleaner build method. Yay!\n        _buildNonsenseWidget(),\n      ],\n    );\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

那么\xe2\x80\x99 到底是什么问题呢?

\n

每当 _counter 的值发生变化时,框架就会调用 build 方法。这会触发我们的小部件重建自身。问题是,每次 _counter 的值发生变化时,都会调用 _buildNonsenseWidget() - 这最终会一遍又一遍地重建小部件树。\n没有任何重建\n在这种情况下,\xe2\x80\x99s 没有理由重建它特定的小部件树。

\n

_buildNonsenseWidget() 返回的小部件树本质上是无状态的 - 我们只需要构建它一次。遗憾的是,由于 widget 树是通过 _buildNonsenseWidget() 方法构建的,因此每次父 widget 重建时,Flutter 框架都会重建它。

\n

本质上,我们\xe2\x80\x99在重建不需要重建的东西时浪费了宝贵的CPU周期。发生这种情况是因为从框架\xe2\x80\x99s 的角度来看,\xe2\x80\x99s 长构建方法和拆分为多个较小方法的构建方法之间没有区别。请注意,这只是一个简单的示例 - 这对更复杂的应用程序有更显着的影响。

\n

拆分长构建方法 - 重新审视\n这个解决方案相对简单,尽管它会导致几行额外的代码。我们没有将构建方法拆分为更小的方法,而是将它们拆分为小部件 - 即 StatelessWidgets。

\n

当我们重构前面的示例时,我们\xe2\x80\x99将得到以下结果:

\n
class _MyStatefulWidgetState extends State<MyStatefulWidget> {\n  int _counter = 0;\n\n  @override\n  Widget build(BuildContext context) {\n    return Row(\n      children: [\n        Text(\'Counter: $_counter\'),\n\n        // The deeply nesting widget is now refactored into a\n        // stateless const widget. No more needless rebuilding!\n        const _NonsenseWidget(),\n      ],\n    );\n  }\n}\n\nclass _NonsenseWidget extends StatelessWidget {\n  const _NonsenseWidget();\n\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      child: Column(\n        children: [\n          Text(\'Hello\'),\n          Row(\n            children: [\n              Text(\'there\'),\n              Text(\'world!\'),\n            ],\n          ),\n        ],\n      ),\n    );\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

结论

\n

不要将构建方法拆分为多个较小的方法,而是将它们拆分为 StatelessWidget。这样,您就不会多次重建静态部件树,而只会浪费 CPU 周期。当谈到优化 Flutter 应用程序的性能时,这可能是最容易实现的目标之一。

\n

我使用了这篇文章:https ://iiro.dev/splitting-widgets-to-methods-performance-antipattern/

\n