1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Flutter-N46.md 11 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 10.03.2025 00:06 5767d61

Небольшие хитрости Flutter: почему рекомендуют использовать константы const для виджетов

Сегодня получил такой вопрос, хотел просто ответить коротко, но решил расширить тему и сделать небольшую статью для более полного объяснения.

Иллюстрация

Перед тем как говорить об этом, стоит вспомнить старый, но золотой принцип: виджеты в Flutter являются неизменяемыми объектами, они не являются настоящими представлениями (views). Виджеты представляют собой лишь конфигурационные данные.

Только поняв этот принцип и соединив его с глубинной неизменяемостью ключевого слова const, можно лучше понять, почему в Flutter рекомендуется использование const для виджетов.

final и const в Dart

Для начала давайте рассмотрим различия между final и const в Dart:

  • final: переменная может быть присвоена значение только один раз, значение определяется во время выполнения программы.

  • const: переменная должна быть компиляционной константой, значение известно до компиляции.

Хотя оба этих ключевых слова используются для создания неизменяемых значений, основное отличие заключается в том, что final используется для значений, определяемых во время выполнения, а const — для значений, известных до компиляции.

finalКонечно, final также создаёт неизменяемое значение, но это значение может быть определено во время выполнения программы. Кроме того, final позволяет использовать позднюю инициализацию (late initialization):```dart

late final String a;

void runResult() { final int result = doSomeThing(); }


То есть, `final` позволяет присваивать значения во время выполнения, после чего они становятся неизменяемыми. Это аналогично тому, как мы можем использовать `final` для создания неизменяемых переменных внутри конструктора виджета:

```dart
class MyHomePage extends StatelessWidget {
  MyHomePage({super.key, this.title});
  final String? title;
}

const

const представляет собой более строгий тип неизменяемости, который определяется до компиляции. Это делает его глубоко неизменяемым, и таким образом он обеспечивает лучшую производительность, так как значения уже известны на этапе компиляции:

const String myConstant = 'Hello';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(myConstant),
    );
  }
}
```Таким образом, использование ключевого слова `const` для виджетов в Flutter помогает улучшить производительность приложения, поскольку все необходимые данные уже известны на этапе компиляции. Константы типа `const` известны во время компиляции, поэтому они оцениваются всего один раз в процессе компиляции, что позволяет Dart-компилятору оптимизировать их использование, экономя память и сокращая время старта. Когда константы типа `const` используются в разных местах, Dart-компилятор выделяет место для них лишь однажды, а значение будет повторно использоваться в других местах, где она привязана. С этой точки зрения, **константы действительно могут повысить производительность и сэкономить память**. Давайте рассмотрим типичный пример объяснения "неизменяемости", как показано ниже:> Можно заметить, что список, объявленный через `const`, имеет внутренние элементы, которые определяются во время компиляции и не могут быть изменены. Кроме того, сам список является константой времени компиляции, а каждый его элемент также является константой времени компиляции.

```dart
const List<int> list = [0, 0, 0, 0, 0, 0];

list[2] = 3;

image

Что касается классов, то конструктор, объявленный через const, требует использования ключевого слова final для всех внутренних переменных, чтобы гарантировать, что объект является неизменяемым и передаваемым. Это обеспечивает целостность статических данных и гарантирует, что объект нельзя будет изменить после его создания.

class Test {
  final int a;
  const Test(this.a);
}

void runTest() {
  const Test test = Test(0);
  test.a = 100;  /// Ошибка
}

Это выглядит знакомым? Да, это именно так — в Flutter такие свойства имеют виджеты. Когда конструктор виджета объявлен через const, все его внутренние переменные должны быть объявлены через final, иначе возникнет ошибка при компиляции.

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key, required this.title});
  final String? title;
}

Без объявления const по умолчанию это будет просто предупреждение: Класс (или класс, от которого этот класс наследуется) помечен как «@immutable», но один или несколько его полей экземпляра не являются final.Кроме того, конструктор, объявленный через const`, также оптимизируется во время компиляции для класса, как показано ниже:

  • Хэш-коды test1 и test2 совпадают
  • Хэш-коды test3 и test4 совпадают
class Test {
  final int a;
  final int b;

  const Test(this.a, this.b);
}

void runTest() {
  const Test test1 = Test(0, 0);
  print("Хэш-код test1: ${test1.hashCode}");
  const Test test2 = Test(0, 0);
  print("Хэш-код test2: ${test2.hashCode}");
  const Test test3 = Test(1, 1);
  print("Хэш-код test3: ${test3.hashCode}");
  const Test test4 = Test(1, 1);
  print("Хэш-код test4: ${test4.hashCode}");
  const Test test5 = Test(2, 2);
  print("Хэш-код test5: ${test5.hashCode}");
}

image

Flutter

Тогда вернёмся к первоначальному вопросу. Поскольку виджеты в Flutter не являются настоящими представлениями (Views), а представляют собой лишь конфигурационные файлы, за которыми скрываются реальные объекты Element и RenderObject, то использование ключевого слова const для объявления этих "конфигураций" позволяет значительно повысить производительность и снизить потребление памяти.

Что же касается того, почему виджеты не считаются настоящими представлениями (Views), более подробно можно прочитать в моих предыдущих статьях. Здесь я приведу простой пример, который часто используется для демонстрации этой идеи:

// Пример кода textUseAll, если это было бы настоящим представлением (View),
// оно не могло бы одновременно использоваться несколькими местами.
```Для Flutter важно отметить, что **Flutter сильно зависит от конфигурационной информации виджетов дерева для отображения интерфейса пользователя. В процессе перестроения (rebuild) при встрече с виджетом, помеченным как const, Flutter распознает его как предварительно созданное и неизменяемое представление**, что позволяет повторно использовать существующие объекты вместо создания новых. Это помогает избежать ненужных вычислений и аллокаций объектов.

> Кроме того, как уже упоминалось ранее, const выполняет оптимизации во время компиляции, такие как предварительное выделение памяти и свертка констант, что позволяет создавать объекты быстрее и снижает количество вызовов сборщика мусора.

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

Итак, не увеличивается ли ваш объём полезных знаний?

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/CarGuo-GSYFlutterBook.git
git@api.gitlife.ru:oschina-mirror/CarGuo-GSYFlutterBook.git
oschina-mirror
CarGuo-GSYFlutterBook
CarGuo-GSYFlutterBook
master