有几种办法能尽量削减build的次数

一、 尽量削减构建办法及其创立的widget所传递创立的节点数量

比方咱们想要定位一个组件的话,考虑运用Align 或许CustomSingleChildLayout,而不是经过组合Row Column、Padding、SizedBox等组件的方式。

与其考虑运用ContainerDecoration的方式来完成想要的图形作用,能够考虑运用CustomPaint组件

二、尽可能的运用const组件,结构函数尽可能的运用const润饰

这是由于const结构函数能让Flutter在构建组件时效率更高,假如widget的装备信息在整个运用生命周期内没有改动,Flutter就能够重用该实例而不是每次构建时都创立一个新的,这样能够削减内存的运用,也削减垃圾回收的压力。

// GOOD
class Page extends StatelessWidget {
 const Page({super.key});
  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}
// BAD
class Page extends StatelessWidget {
// 尽量运用const润饰结构函数
  Page({super.key});
  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

三、假如组件由于InheritedWidget可能会频频的rebuild,能够考虑将组件重构为多个组件,将有可能重构的widget放到叶子结点。

四、假如子树不会改动,能够缓存代表该子树的widget,并在每次运用时重用它。

咱们能够将该widget分配给一个final润饰的状况变量,并在build办法中重用它。
重用widget比创立一个新的(装备相同的)widget高效的多。另一种缓存战略是将widget的可变部分提取到承受child参数的StatefulWidget组件中

五、尽量避免创立的子树的深度或改动子树中任何widget的类型。

这是由于改动子树的深度需求重建、布局和绘制整那个子树,而仅改动属性将对烘托树进行最小的改动。
比方

// GOOD
  @override
  Widget build(BuildContext context) {
    final child = Container();
    return IgnorePointer(
      ignoring:ignoring,
      child: child,
    );
  }
// BAD
 @override
  Widget build(BuildContext context) {
    final child = Container();
    if(ignoring) {
      return child;
    }
    return IgnorePointer(
      child: child,
    );
  }

假如必需求改动深度的话,能够考虑将子树中的公共部分包装在有GlobalKey的widget中,这样就能够在stateful widget中保持一致。(假如没有合适的widget设置key,能够运用KeyedSubtree widget)

六、当有一部分UI能够重复运用的时分,优先考虑封装成一个单独的widget,而不是经过辅佐办法。

这是由于,假如经过办法构建一个widget,当调用setState时,build全体都会从头运转,Flutter会完全重构该办法返回的widget,这样非必要的UI重建,可能会导致element树和render object树这类的树结构糟蹋CPU时间。尤其是在履行动画的时分。

假如是一个Widget的话,Flutter就能够有效的仅从头烘托确实需求更新的部分。并且,假如该widget是 const 的话,Flutter将能够缩短大部分的rebuild工作。

并且辅佐办法可能领会外的持有过时的context,比方

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});
  @override
  Widget build(BuildContext context) {
    return Builder(builder: (innerContext) {
      return IconButton(
        onPressed: () {
          Theme.of(context)...
        },
        icon: const Icon(Icons.favorite),
      );
    });
  }
}

在Builder组件中咱们context定义了不同的称号innerContext,在其嵌套代码中就有可能运用旧有而不稳定的context,而假如运用封装widget的话就能避免这样的过错:

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});
  @override
  Widget build(BuildContext context) {
    return Builder(builder: (innerContext) {
      return MyIconButton();
    });
  }
}
class MyIconButton extends StatelessWidget {
  const MyIconButton({super.key});
  @override
  Widget build(BuildContext context) {
    return IconButton(
      onPressed: () {
        Theme.of(context)...
      },
      icon: const Icon(Icons.favorite),
    );
  }
}

这样widget就能访问仅有且正确的context了。

总的来说,官方仍是引荐运用widget来拆解庞大的build办法的。

办法仍是widget其实也引起了许多的评论,能够看下stackoverflow的评论。这里的高赞列举了几个运用类的优点:

  1. 性能优化:

    • 运用const结构函数能够创立不变的组件,这能够协助Flutter框架在需求时避免不必要的重建。
    • 类能够完成更精密的重建操控,比方经过StatefulWidgetsetState办法或许运用Provider等状况办了解决方案。
  2. 资源办理:

    • 类能够确保在组件树中切换布局时,正确地开释旧布局所运用的资源。相比之下,函数可能领会外地重用之前的状况。
  3. 热重载:

    • 类能够确保热重载(hot-reload)功用正确工作。运用函数可能会损坏showDialog和类似功用的热重载能力。
  4. 工具集成:

    • 类组件会被Flutter DevTools中的Widget Inspector辨认并显示在组件树中,这有助于开发者了解屏幕上显示的内容。
    • 能够重写debugFillProperties

参阅链接:

  1. api.flutter.dev/flutter/wid…
  2. api.flutter.dev/flutter/wid…
  3. stackoverflow.com/questions/5…