Помните декларативные языковые характеристики Flutter

HTML - это декларативный язык программирования. Это язык разметки, который представляет текстовым шрифтом и символами веб-страницу в определенный момент времени. Слово, используемое здесь, очень важно. HTML «представляет», а не «представляет» веб-страницу. Это браузер, который выполняет всю фактическую работу - он читает HTML, выполняет рендеринг, а затем представляет веб-страницу со всем ее текстом, ее строками, кнопками, формами и т. Д. Когда все доходит до этого, HTML - это просто инструкция.

Когда вы смотрите на необработанный исходный код HTML, вы смотрите на «статическое представление» или снимок того, как должна выглядеть веб-страница (а также потенциально то, что она способна делать) в данный момент. Этот текст в этот самый момент неизменен. Неизменный. Только с новым запросом HTML веб-страница "изменит" свое содержание. Обратите внимание, что во многих случаях изменение заключается не в изменении существующего HTML здесь и там, а в повторном создании всей страницы с нуля. Хотя это и не очевидно, но это эффективный подход. Сам HTML занимает мало памяти. В конце концов, это просто инструкции.

Видите ли, Flutter - это псевдодекларативный UI-фреймворк. Он имеет характеристики императивного, реактивного и функционального программирования, но именно его характеристика декларативного языка использует подход «перестройки с нуля». При каждом вызове функции build (), например, из объекта State или виджета без состояния, возвращаемый виджет чаще всего создается заново заново. Код Dart в этой функции build () - это просто инструкции. Все визуализации выполняет движок Flutter. На самом деле весь процесс требует мало ресурсов памяти и довольно быстр. Теперь, чтобы сделать его еще легче и быстрее: подумайте о HTML. Мыслите декларативно. Думайте неизменным.

Мне нравятся скриншоты. Щелкните для Gists.

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

Давай начнем.

Держите его неизменным

Когда вы впервые начали изучать Flutter, я не сомневаюсь, что вы столкнулись с ошибкой, по сути говоря: «Этот класс отмечен как '@immutable', но одно или несколько его полей экземпляра не являются окончательными». Ниже приведен снимок пресловутого «стартового приложения» (или приложения счетчика), которое поставляется с каждым новым проектом Flutter. Ключевое слово final было удалено из поля экземпляра title в StatefulWidget, MyHomePage, и появилось это предупреждающее сообщение.

Глядя на этот пример, помните, что StatefulWidget создается, уничтожается и воссоздается снова и снова в течение жизни типичного приложения Flutter. Как и внутри функций build (), здесь реализован декларативный подход. Сделайте одолжение своему приложению Flutter и не игнорируйте такие предупреждения. Такие «изменяемые» поля экземпляра занимают память и используют больше циклов ЦП при выполнении. На самом деле, давайте еще раз взглянем на это пресловутое приложение-счетчик и посмотрим, сможем ли мы сократить его производительность на несколько миллисекунд. Ниже приведен снимок приложения счетчика. То, с чем мы все должны быть знакомы.

Теперь посмотрите на версию приложения счетчика ниже. Когда вы запустите его, он будет выглядеть точно так же (ну, он будет зеленым, а не синим). Однако этот работает быстрее и, вероятно, имеет меньший объем памяти по сравнению. Маленькие красные стрелки указывают, почему. Вы увидите намного больше final и const ключевых слов.

Если ваше приложение создает объекты, которые никогда не меняются, вы должны сделать эти объекты константами времени компиляции. Движок Flutter полюбит вас за это! Вы делаете это с помощью ключевого слова const.. Кроме того, используйте const для любых полей экземпляра, которые также должны быть константами времени компиляции, чтобы они оставались неизменными на протяжении всего времени существования приложения. Такие переменные содержат значение еще до того, как вы запустите приложение! Это большая помощь движку Futter - меньше работы.

Даже целый класс может быть постоянным! Неизменный. Вы делаете это, предоставляя классу «постоянный конструктор». Вы делаете это, помещая ключевое слово const перед именем конструктора. Это означает, однако, что все поля экземпляра, если они есть в этом классе, объявляются окончательными. Если вы можете управлять этим для своих классов, ваше приложение станет намного быстрее.

На скриншоте ниже вы можете увидеть, как мы сообщаем компилятору, что неизменяемо в коде, и поэтому оптимизируем его соответствующим образом. Вы можете видеть, например, что поле экземпляра title объявлено окончательным, и поэтому его класс MyHomePage может и должен иметь константный конструктор.

Многие поля экземпляра инициализируются непосредственно из параметра конструктора. Этот процесс описывается как «формальная инициализация» и включает использование синтаксиса this. перед параметром конструктора. Таким образом, именованный параметр является полем экземпляра и инициализируется прямо в списке параметров. Такие поля экземпляра должны быть объявлены окончательными, если в течение жизненного цикла класса этим полям никогда не будет присвоено другое значение. Опять же, как вы видите ниже, поле экземпляра title является одним из таких примеров.

Переменные / поля экземпляра, объявленные как final, должны быть инициализированы до запуска тела конструктора класса. Как указано выше, один из способов инициализации таких полей экземпляра - это использование параметров в конструкторе класса. Однако поля экземпляра также могут быть объявлены окончательными, когда они инициализируются в списке инициализаторов конструктора. Вы можете увидеть это в обновленной версии приложения счетчика. См. ниже.

Добавьте немного линта в свой код

На самом деле не добавляйте Lint в свой код. «Линт» в этом контексте описывает программные и стилистические ошибки, обнаруженные в коде. Более подходящим было бы высказывание: «Добавьте ЛИНТЕР в свой код». ЛИНТЕР - это инструмент статического анализа кода, используемый для выявления таких проблем.

Со временем, работая с Flutter, вы легко обнаружите в коде места, где было бы уместно использовать const или final. А пока почему бы не позволить вашему ЛИНтеру выбрать их за вас? Например, в большинстве IDE, если вы забудете точку с запятой в конце строки, вы, скорее всего, увидите на экране небольшую красную линию, указывающую на проблему. Это анализатор Dart, выполняющий свою работу над вашим кодом. Он должен указывать на такие ошибки, а также указывать предупреждения о коде, который не соответствует собственным спецификациям языка Dart.

Однако вы можете дополнительно настроить ЛИНТЕР (специальный плагин анализатора, который выполняет линтинг), чтобы следить за случаями, когда ключевые слова final и const будут уместны в вашем код.

Основная статья ITomek Polański, названная Строгие правила Flutter Lint, отлавливает такие случаи и многое другое. Это действительно хороший подход, который заставит вас сделать свой код эффективным и действенным, а также соответствовать признанным стандартам. Чтобы использовать эти правила, вы просто копируете их все в файл опций анализа, analysis_options.yaml который вы создаете в корне вашего проекта, где находится ваш pubspec.yaml файл. Затем среди вашего кода появятся маленькие серые линии, указывающие на предупреждения - обратите внимание на эти предупреждения, и вам будет лучше.

Сохраняйте эффективный стиль

Кстати, чтобы хотя бы убедиться, что ваш код соответствует Руководству по стилю Dart или следует рекомендациям, содержащимся в Effective Dart, вам доступны некоторые дополнительные правила ЛИНТЕР. Они могут быть не такими строгими, как приведенные выше, но у них есть много одинаковых правил, и они даже пересекаются друг с другом. Эти два отдельных руководства представлены двумя отдельными наборами правил ЛИНТЕР. Во-первых, вы должны объявить любую из них зависимой от разработчиков в вашем pubspec.yaml файле:

dev_dependencies:
  pedantic: ^1.0.0
OR
dev_dependencies:
  effective_dart: ^1.0.0

Затем введите команду pub get, чтобы добавить эту зависимость в свой проект. Наконец, включите их набор правил с помощью следующей командной строки, введенной в начале вашего файла параметров анализа, analysis_options.yaml

include: package:pedantic/analysis_options.yaml
OR 
include: package:effective_dart/analysis_options.yaml

Сведите количество изменяемых к минимуму

Таким образом, сведение к минимуму изменяемых элементов вашего приложения действительно поможет повысить общую производительность вашего приложения. Итак, что касается этого счетчика, где счетчик? Единственное, что мы знаем, в этом приложении можно изменить.

Что ж, сохранение изменяемой части вашего приложения на своем месте также имеет свои преимущества. Обратите внимание, что в измененной версии объект State _MyHomePageState имеет одно единственное поле экземпляра, называемое bloc, и оно также объявлено как final. Итак, что это за блочная штуковина?

Это поле экземпляра, которое ссылается на совершенно отдельный класс! Я назвал класс Bloc, чтобы намекнуть, что он содержит задействованную «бизнес-логику» - какую небольшую бизнес-логику есть для такого простого приложения. Конечно, создание еще одного класса в этой версии снижает производительность, но вы все равно обнаружите, что он быстрее.

В качестве плюса я представил вам подход к организации вашего кода. Фактически, это подход, который вы, несомненно, в той или иной форме применили в своих приложениях. Я имею в виду, что вы могли бы просто иметь всю бизнес-логику вашего приложения и обработку событий в своем объекте State, но это будет довольно большим и беспорядочным объектом State. Нет? У ваших объектов State по-прежнему есть доступ к этому материалу, но он управляется в отдельных классах. Это вариант.

В дизайне есть узор

Глядя на этот отдельный класс, вы можете распознать этот подход как общую черту, обнаруженную во многих шаблонах проектирования, которые в настоящее время предлагаются разработчикам Flutter. Это подход, который также помогает нам в наших усилиях по превращению как можно большей части приложения в «статическое представление» того, как это приложение должно выглядеть (и что оно потенциально может делать) в определенный момент времени. Конечно, маленькие красные стрелки выделяют код в функции build (), который далеко не неизменен - ​​они вычисляются во время выполнения. Однако эти изменяемые компоненты теперь в основном находятся в одном месте. В классе Bloc. Видите здесь немного закономерности? Это способствует низкому сцеплению и простоте обслуживания.

В любом случае, оставим это здесь. Во всяком случае, следование правилам Lint, описанным выше, только сделает вас лучшим разработчиком Flutter. Это один вывод, правда?

Ваше здоровье.

→ Другие рассказы Грега Перри

Следите за сообществом Flutter в Twitter: https://www.twitter.com/FlutterComm