StatelessWidget против функции, возвращающей виджеты с точки зрения производительности

Есть ли разница в производительности при использовании StatelessWidget против function returning a Widget?

Я хорошо знаю, по крайней мере, различия, указанные в проблеме репо этого флаттера, которые не связаны с производительностью.

Дело в том, что у меня есть коллеги, утверждающие, что functional widgets худшие с точки зрения производительности, но после прочтения немного о предмете я не могу найти какой-либо убедительной части документации, которая могла бы подтвердить это утверждение, поэтому любые разъяснения по этому вопросу будут очень приветствоваться!

Насколько я вижу, единственное различие между ними было бы в случае использования const Widget Кажется, что это позволит избежать этапа восстановления.

1 ответ

Прежде всего, я хотел бы отметить, что пакет доступен для StatelessWidget из функции: functions_widget


Выигрыш в производительности не обязательно соответствует действительности. Это зависит от того, как вы используете свои виджеты, в основном от того, как вы используете их для управления своим состоянием.

По умолчанию классы могут ухудшать производительность, в отличие от функций в приложении, которое не использует их мощность.

Реальный вопрос: в чем их сила?

Просто: классы могут обновляться независимо друг от друга. Функции не могут

Классы могут частично обновлять дерево виджетов.

Рассмотрим виджет, который перестраивает каждый кадр и возвращает его дочерний элемент:

class InfiniteLoop extends StatefulWidget {
  const InfiniteLoop({Key key, this.child}) : super(key: key);
  final Widget child;
  @override
  _InfiniteLoopState createState() => _InfiniteLoopState();
}

class _InfiniteLoopState extends State<InfiniteLoop> {
  @override
  Widget build(BuildContext context) {
    WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {}));

    return widget.child;
  }
}

Что будет, если мы поместим все наше приложение в этот виджет?

void main() => runApp(InfiniteLoop(child: MyApp()));

Ничего такого

Конечно, у вас будет один виджет, который часто перестраивается в вашем дереве. Но на самом деле build метод MyApp будет вызван только один раз.

Это потому, что Flutter может прервать перестроение дерева, когда экземпляр виджета не изменяется.


Классы могут злоупотреблять этой оптимизацией.

Используя классы, можно разумно разделить перестройку дерева виджетов на независимые части.

Нецелесообразно перечислять все потенциальные факторы оптимизации, которые допускает класс, так как их слишком много.

В следующем примере приведен виджет, который принимает int и форматирует его в Text, Уловка в том, что этот виджет будет перестраиваться только если int прошло изменение:

class Counter extends StatelessWidget {
  const Counter({Key key, this.value}) : super(key: key);

  final int value;

  @override
  Widget build(BuildContext context) {
    return Text(value.toString());
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) || (other is Counter && other.value == value);

  @override
  int get hashCode => value.hashCode;
}

Это работает, потому что Flutter использует == Оператор, чтобы узнать, должен ли виджет обновляться или нет (следовательно, почему const конструктор является хорошим фактором оптимизации).

Это не единственное решение, но это хороший пример того, что функции не могут сделать.

Другие вопросы по тегам