在小部件树中使用const是否可以提高性能?

Noa*_*man 10 dart flutter

创建小部件树时,const在静态小部件之前插入会提高性能吗?

child: const Text('This is some text');
Run Code Online (Sandbox Code Playgroud)

child: Text('This is some text');
Run Code Online (Sandbox Code Playgroud)

我知道,使用Dart 2 const是可选的,并且在某些地方会自动插入。这是其中一种情况吗?如果不是,使用会const减少内存使用/提高性能吗?

感谢您的回答!

Gün*_*uer 34

这是一个小的性能改进,但它可以在较大的应用程序或经常重建视图的应用程序中累积,例如由于动画。
const减少垃圾收集器所需的工作。

您可以启用一些 linter 规则analysis_options.yaml,告诉您何时应该添加,const因为它不是推断出来的,但可能像

或者在你使用时提醒你const但它是推断出来的

另见https://www.dartlang.org/guides/language/analysis-options

  • 不,您需要自己进行基准测试。这也可能会发生变化,具体取决于您是在 VM(Flutter 调试模式、控制台应用程序)中运行它、编译为 JS 还是在 Flutter 发布模式中运行。const 值是规范化的,并且内存中只有一个类的实例具有一组特定的构造函数参数。无论您创建多少个这样的唯一值,Dart 始终使用相同的实例,并且垃圾收集器永远不会收集它。因此,它很可能会提高性能,尤其是对于经常重新创建的静态 Flutter 小部件。 (3认同)

Ced*_*Ced 8

更新: 我注意到我最近收到了一个赞成票,我必须说我下面的测试可能是错误的。所以最好有人进行更好的测试。


我已经进行了一些测试,看看它是否有所作为。

这些测试主要基于本文中所做的测试。

对于测试,有 300 个容器,里面的文本在屏幕上随机移动。您在日常应用程序中不会看到的东西。

对于我的结果,每秒帧数和内存使用量没有区别,只是垃圾收集器在不使用 const 时似乎运行得更频繁。同样,FPS 大致相同。

内存使用情况图片

Imo,性能提升可以忽略不计,听起来像是抢占式优化。然而,测试中没有深度嵌套的小部件链,但我看不出这会有什么不同。上面的文章似乎说有一个小的,但这不是我的测试显示的。

我有一张这样的卡(这是 const 版本):

import 'package:flutter/material.dart';

class MyCard extends StatelessWidget {
  const MyCard();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Container(
        margin: const EdgeInsets.all(8.0),
        height: 100,
        width: 100,
        color: Colors.red,
        child: const Text('Hi'),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

它被渲染了 300 次并在屏幕上随机移动。

这是让他们移动的小部件

import 'package:flutter/material.dart';
import 'dart:math';
import 'dart:async';
import './my-card.dart';

class MovingContainer extends StatefulWidget {
  @override
  _MovingContainerState createState() => _MovingContainerState();
}

class _MovingContainerState extends State<MovingContainer> {
  final Random _random = Random();
  final Duration _duration = const Duration(milliseconds: 1000);
  Timer _timer;
  double _top = 0;
  double _left = 0;

  @override
  void initState() {
    super.initState();
    initMove();
  }

  void initMove() {
    _timer = Timer.periodic(
      _duration,
      (timer) {
        move();
      },
    );
  }
  void move() {
    final Size size = MediaQuery.of(context).size;
    setState(() {
      _top = _random.nextInt(size.height.toInt() - 100).toDouble();
      _left = _random.nextInt(size.width.toInt() - 100).toDouble();
    });
  }

  @override
  void dispose() {
    _timer.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedPositioned(
      top: _top,
      left: _left,
      child: const MyCard(),
      duration: _duration,
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

注意:我是 flutter 的新手,其他许多人也是如此,因为它是一个相对较新的框架。因此我的测试很可能是错误的,不要把它当作福音。当您阅读一篇名为《Flutter 性能第一》的文章时,也不要将其视为福音。我还没有看到有性能提升的实际证据。抢占式优化是一个甜蜜的谬论。

  • 这表明做自己的基准测试总是很重要:)我不同意“几十个”小部件。在材料设计应用程序中,小部件树非常大,因此非常麻烦,因为有数百个小部件。仍然不是一个巨大的数字(数千)。我首先尝试构建一个使设备达到极限的应用程序,然后检查使用 const 是否会产生影响。只要设备有足够的电量来执行 GC 而不会造成延迟,无论如何都没关系。 (2认同)

Rém*_*let 6

在颤振的情况下,真正的收获const具有较少实例。当窗口小部件的实例不变时,Flutter具有特殊的处理方式:它不会重建它们。

考虑以下:

Foo(
  child: const Bar(
    child: Baz() 
  ),
)
Run Code Online (Sandbox Code Playgroud)

如果build再次调用方法(setState,父级重建,Inheritedwidget...),则由于constfor Bar子树,只会Foo看到其build方法被调用。

Bar永远不会得到重建,因为其母公司,因为扑知道,因为小部件实例并没有改变,没有什么更新。

  • 它不需要是常量才能起作用。如果返回相同的实例,它将具有相同的效果。使用const时,它总是自动总是同一实例。 (2认同)
  • 确实,但是这种优化的最常见用法是使用const(或使用child / children)。 (2认同)