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

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

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

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

Содержание может быть достаточно объемным, но я уверен, что это поможет вам лучше понять Flutter.

Происхождение Flutter

Происхождение Flutter довольно интересно. Flutter зародился как внутренний эксперимент команды Chrome. Эксперты Google перед тем, как удалить некоторые "нестабильные" нормы фронтенда, заметили, что производительность увеличилась в 20 раз. Это случайное открытие привело к созданию Flutter.

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

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

Поэтому когда Flutter был представлен миру, ему пришлось столкнуться со следующими проблемами:- Для разработчиков нативных клиентских приложений декларативный способ разработки сразу вызывает дискомфорт, поскольку они привыкли к разделению кода и макета (Java/Kotlin + XML) и процедурному объектному программированию; декларативный подход требует дополнительных усилий для обучения; они также считают, что вложенность в Flutter "отвратительна".- Для разработчиков фронтенда установка среды Flutter очень сложна: помимо VSCode и Flutter SDK требуется установка таких нативных инструментов, как Java, Gradle, Android SDK, Xcode и других "вне круга" переменных окружения (часто возникают проблемы с сетью); знания необходимых для работы с Flutter нативных платформ для фронтендера являются неприятными; они также считают, что вложенность в Flutter "омерзительна".

Обратите внимание, что я не говорю о Dart как о затрудняющем обучение языке, так как для специалистов по JavaScript, Java, Kotlin или Swift Dart выглядит как "младший брат".

Кроме того, как фронтендеры, так и разработчики нативных приложений будут критиковать вложенность в Flutter, однако насколько серьёзна эта проблема? Мы поговорим об этом позже.

В целом, для начинающих фронтендеров или разработчиков нативных приложений, Flutter представляет собой определённые препятствия и психологический барьер. Но есть ли причины обязательно учиться Flutter для фронтендера или разработчика нативных приложений?### Причины учиться Flutter

При общении с новичками в Flutter, очень часто можно заметить, что они вынуждены использовать этот фреймворк, так как руководство требует его применения, поэтому приходится "неохотно" начинать обучение Flutter — это одна из самых весомых причин: "руководитель хочет", если вы не хотите менять работу.#### 1. Уровень личной конкурентоспособности

Разработка программного обеспечения — это интересная сфера, где мы часто сталкиваемся с тем, что после длительного использования одной технологии начинаем считать её популярной, а все остальные — устаревшими. Особенно это происходит под влиянием "СМИ", когда эффект "беременной женщины" приводит к ошибкам восприятия.

В середине прошлого года я провёл анализ данных по 53 образцам в статье "Анализ внедрения кросс-платформенных фреймворков мобильными гигантами Китая". В результате анализа были получены следующие данные: Flutter (19), Weex (17), React-Native (22). Ниже представлен график, отражающий количество производственных приложений, использующих Flutter, собранных со смартфона с помощью libChecker.

График количества приложений, использующих Flutter

Этот пример показывает, что Flutter уже не является малоизвестным фреймворком; за последние два года он стал одним из основных кросс-платформенных фреймворков.

Поэтому Flutter действительно может помочь вам найти работу, но я бы не рекомендовал начинать изучение именно с него, потому что Flutter представляет собой лишь кросс-платформенный UI-фреймворк.> Очень важно понять эту фразу, чтобы избежать навязывания бесполезного стресса, поскольку хотя Flutter поддерживает мобильные устройства, веб-браузеры и ПК, как UI-фреймворк он помогает решать проблемы с кросс-платформенным UI и частью бизнес-логики, но функции, связанные с платформой, такие как Bluetooth, взаимодействие с платформой, хранение данных и сборка, требуют поддержки native.На текущий момент все кросс-платформенные фреймворки, будь то Flutter, React-Native или Weex, имеют одну цель: решение проблем с кросс-платформенным UI и бизнес-логикой, и их развитие невозможно без поддержки native платформ.

Если native платформа прекратит существование, то говорить о кросс-платформенности будет бессмысленно. Например, кто сейчас говорит о необходимости кросс-платформенного развития для Windows Phone? Поэтому Flutter и native платформы должны развиваться вместе, а не противостоять друг другу, они находятся в состоянии паразитизма и симбиоза, и без опыта работы с native платформами сложно добиться удовлетворения от использования Flutter. Но сейчас Flutter действительно может помочь в вашем карьерном развитии, так как он позволяет расширять ваши возможности в области бизнес-разработки, позволяя участвовать в разработке на различных платформах, будь то фронтенд или KPI. Конечно, такие технологии, как React Native и Uni-app, тоже могут это предоставить, возможно даже с меньшими затратами для фронтенд-разработчиков, но почему стоит выбрать Flutter?

На самом деле есть еще один интересный момент: знание Flutter для нативной разработки Android равноценно знанию более чем 70% Jetpack Compose.

2. Консистентность FlutterНа самом деле я всегда рекомендую клиентам учиться Flutter, потому что для фронтенд-разработчиков React Native и Uni-app действительно являются более выгодными вариантами, хотя, кажется, руководители и владельцы компаний не согласны с этим.Тогда какие дополнительные преимущества предоставляет использование Flutter? Это производительность и консистентность Flutter.

Потому что Flutter является UI-фреймворком, он действительно кросс-платформенный! Почему важно подчеркнуть "настоящую кросс-платформенность"? Потому что в отличие от React Native и Weex, компоненты Flutter не создаются через нативные компоненты, а используются платформенно-независимые возможности рендера, предоставленные движком Flutter. То есть компоненты Flutter не зависят от платформы.

Проще говоря, нативная платформа предоставляет Surface, который используется как холст, а затем все остальное рендерится Flutter, и этот процесс завершается сборкой в виде бинарного файла AOT.

Поэтому UI-компоненты Flutter могут обеспечивать консистентность во всех аспектах, что очень важно для меня. Почему именно так? Для этого стоит сравнить его с React Native.

Потому что React Native использует преобразование компонентов JavaScript в нативные компоненты для рендера, поэтому компоненты React Native зависят от нативных компонентов платформы. Из-за различий между нативными компонентами различных систем и различиями свойств и эффектов одного компонента в разных версиях одной системы, объединённые вместе, они становятся значительной стоимостью обслуживания при дальнейшей разработке.image

Во время моего опыта работы с React Native мне часто приходилось сталкиваться с ситуациями:

  • Стили, отлаженные на iOS, вызывали проблемы на Android;
  • Стили, работающие на Android, не имели поддержки на iOS;
  • Эффекты компонентов на iOS были представлены по-другому на Android, например, при прокрутке страницы или использовании AppBar;

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

В некотором роде можно сказать, что Flutter больше похож на легкий игровой движок вроде Unity, но он предоставляет 2D компоненты.

Конечно, такой подход у Flutter имеет и недостатки, в частности, когда требуется использование компонентов платформы при гибридной разработке, затраты и опыт использования Flutter значительно увеличиваются, а здесь react-native имеет значительное преимущество.

Какие характеристики производительности Flutter?На самом деле, ранее уже было упомянуто, что производительность Flutter обычно выше, чем у React Native. Об этом есть статья "Flutter против React Native против Native: глубокий анализ производительности", которая проводит более детальное сравнение. Здесь мы хотим обратить внимание на несколько распространённых заблуждений:

    1. Производительность Flutter в режимах отладки и выпуска отличается существенно из-за различий между JIT и AOT компиляцией.
    1. Не следует проверять производительность на симуляторе, так как это бесполезно — на реальных устройствах Flutter гораздо больше зависит от мощностей графического процессора.
    1. Гибридная разработка с использованием Flutter может негативно влиять на производительность. Например, если вы замените часть бизнес-логики существующего проекта Android на Flutter, это будет серьёзным испытанием для производительности и памяти. Причины этого заключаются в том, что независимое управление компонентами и стеком вызовов Flutter может привести к негативным последствиям.
    1. То же самое приложение, реализованное разными людьми, может работать по-разному. Обычно для обычных разработчиков популярные фреймворки не создают больших бутылок в плане производительности; чаще всего ограничивающим фактором является уровень мастерства разработчиков.### Как учиться Flutter?

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

Реактивное программирование

Реактивное программирование должно быть знакомо любому фронтендеру, эту тему для фронтенд-разработчиков можно пропустить, поскольку реактивное программирование также известно как декларативное программирование, которое стало основным направлением развития фронтенд-разработки. Это также тренд в клиентских технологиях, таких как Jetpack Compose и SwiftUI.

Подобие между Jetpack Compose и Flutter точно удивит вас.

Что такое реактивное программирование? Проще говоря, это то, что вам не нужно самостоятельно обновлять интерфейсы; достаточно "объявить" интерфейс через код, установить связь между данными и интерфейсом, и при обновлении данных интерфейс автоматически обновится. С точки зрения кода, для нативного программирования в реактивной разработке отсутствуют XML-шаблоны для размещения, все размещение полностью выполняется с помощью кода, то есть вы видите то, что получаете, при этом вам не требуется использовать объекты интерфейса для присваивания значений и обновлений; вам просто нужно настроить отношения между данными и интерфейсом.Пример:

  • В прошлом на Android вам требовалось создать XML, затем разместить TextView, получить этот объект через findViewById и установить значение с помощью setText;
  • Сейчас в Flutter вам достаточно объявить Widget Text и передать данные, такие как data.title, прямо этому Text; когда данные меняются, содержимое отображаемого текста также обновляется;

image

Для разработки на Android некоторые могут подумать, что это аналогично MVVM и Data Binding. Однако это немного отличается. Более наглядный пример можно взять из презентации босса "扔物线" на конференции Google I/O о Jetpack Compose, почему Data Binding не является реактивной разработкой:

Потому что Data Binding (будь то конкретная библиотека или подход к программированию) не может обеспечить «объявление UI», другими словами, объявление UI — это более мощная форма данных, чем простое связывание данных. Например, в Compose вы можете не только связывать значения строк, но и использовать логические типы данных для управления существованием элементов интерфейса. Например, создайте ещё одну логическую переменную и используйте её для управления отображением вашего текста:

image> Обратите внимание, когда show сначала равно true, а затем становится false, это не значит, что было установлено setVisibility(GONE). Вместо этого Text() исчезает из кода интерфейса, каждый раз, когда данные изменяются, обновление интерфейса происходит так, будто он был закрыт и снова открыт с новыми данными. Это называется декларативной моделью UI, которую нельзя реализовать с помощью Data Binding.

Конечно, Compose не реинициализирует весь интерфейс заново, он обновляет только те части, которые действительно требуют обновления, таким образом гарантируя, что автоматическое обновление интерфейса будет столь же эффективным, как и ручное обновление. В Flutter ситуация аналогична: когда вы используете такие значения как true и false для управления расположением, это непосредственно влияет на структуру дерева виджетов и более глубокую логику рендера. Поэтому людям, переходящим с Android на Flutter, следует привыкнуть к этому подходу и "отказаться" от идеи сохранения или удерживания какого-либо компонента интерфейса после получения данных. Кроме того, в Flutter удерживание какого-либо виджета для его модификации большинством случаев не имеет смысла, и это тема нашего следующего обсуждения. #### 2. Внешняя оболочка виджетаВ Flutter всё является Widget, Widget является неизменяемым (immutable), каждый Widget представляет состояние кадра.

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

Widget является неизменяемым, что означает, что при изменении страницы Widget обязательно будет перестроен. Неподвижное состояние Widget представляет собой статичное изображение кадра, а когда изображение меняется, соответствующий Widget также изменится.

Рассмотрим пример, который я часто привожу. Ниже показана реализация TestWidget, которая принимает входные параметры title и count и отображает их с помощью Text. При этом если значение count больше 99, то отображается только 99.


/// Предупреждение
/// Этот класс помечен как '@immutable', но один или более его экземплярных полей не являются final
class TestWidget extends StatelessWidget {

  final String title;

  int count;

  TestWidget({this.title, this.count});

  @override
  Widget build(BuildContext context) {
    this.count = (count > 99) ? 99 : count;
    return Container(
      child: new Text("$title $count"),
    );
  }
}

Этот код выглядит корректным и работает правильно, однако компилятор выдает предупреждение "This class is marked as '@immutable', but one or more of its instance fields are not final", потому что внутренний член count класса TestWidget не объявлен как final, что может вызвать путаницу на уровне кода.> Поскольку было указано, что Widget является immutable, каждое изменение приведёт к тому, что Widget будет перестроен заново. Это значит, что член count внутри TestWidget фактически не сохраняется и не используется повторно.

Как показано выше, если член count не объявлен как final, теоретически можно дважды модифицировать и переопределить значение count, создающую иллюзию того, что он сохраняется и используется повторно внутри TestWidget, что может вызывать путаницу, особенно если рассматривать widget.count в некоторых случаях. Поэтому использование ключевого слова final помогает понять логику неизменяемости Widget.

Если заменить StatelessWidget на StatefulWidget и переместить метод build внутрь State, то член count внутри State сможет сохраняться между кадрами. Основной идеей здесь является понимание неизменяемого свойства Widget, а также осознание того, как можно использовать State для хранения и восстановления данных между Widgets.

Это связано с ещё одним важным понятием в Flutter — тем, что находится за кадром Widget. В действительности Widget в Flutter не являются реальными компонентами управления. Widget скорее всего выступает в роли конфигурационного файла, тогда как Element, RenderObject и Layer выполняют реальные операции.

Основное внимание следует уделять Element, RenderObject и Layer.Примером может служить следующий код, где Text с именем testUseAll используется трижды на одной странице, и при этом код корректно отображается. Если бы это был настоящий View, он не смог бы использоваться одновременно несколькими местами на одной странице.

Иллюстрация

В Flutter Widget представляет собой конфигурацию, которая сообщает Flutter, как именно должна происходить отрисовка. Widget проходит через Element, RenderObject и даже до уровня Layer, прежде чем происходит окончательная отрисовка. Поэтому Widget может быть помечен как @immutable, так как каждый раз при обновлении состояния он будет перестраиваться заново.

Поэтому вернёмся к первому вопросу: "Наследование в Flutter очень сложное?" Да, настройки Flutter действительно приводят к тому, что есть объективные факты наследования, но когда вы начинаете рассматривать Widget как конфигурационный файл, вы можете лучше организовать свой код, например, Container в Flutter является абстрактным шаблоном конфигурации.

Изучите Container, чтобы узнать первый шаг организации логики кода в Flutter.Кроме того, поскольку Widget не выполняет реальных операций, то на самом деле "наслоение" не является наслоением Views, поэтому обычно наслоение Widgets не вызывает проблем производительности, так как они не выполняют реальные операции, и наслоение не приводит к значительному снижению производительности. Приведу пример: когда вы загружаете несколько Widget, то при первой загрузке создается Element. В последующих загрузках Element хранит в себе Widget и RenderObject.Кратко говоря, обычно изменения экрана представляют собой обновление состояния Widget, которое затем передается RenderObject. В Flutter состояние (State) можно сохранять между кадрами благодаря тому, что оно находится внутри Element. Это позволяет сохранять данные между различными Widget.

Таким образом, вложенность Widget обычно не приводит к проблемам производительности, так как каждый Widget представляет собой состояние одного кадра. Можно сказать, что это "конфигурационная информация", которая отражает текущее состояние экрана. За каждым Widget скрывается вложение таких компонентов, как Padding и Align, которые в конечном итоге сводятся к простому смещению на канвасе.

Поэтому важно понимать Widget: они не являются настоящими представлениями (Views), а лишь содержат конфигурацию. Только осознав это, вы сможете лучше понять широкие возможности Flutter, такие как:

  • Реальные рабочие объекты в Flutter начинаются с Element;
  • Чтобы понять, как реализовано конкретное представление Widget, следует обратиться к его RenderObject;
  • Чтобы понять, почему различные страницы не мешают друг другу, стоит изучить логику их Layers;
  • Обязательно ли все Widget имеют RenderObject? Какова связь между Widget, Element, RenderObject и Layer?**Это именно те вещи, которые вам нужно понять и объединить, чтобы стать экспертом в Flutter. Когда вы поймёте сложную логическую основу за Widget, вы заметите, насколько просто Flutter может решать задачи создания сложных компонентов. Возможности Canvas действительно великолепны.**Конечно, подробное рассмотрение этих тем требует более глубокого анализа, чем можно было бы сделать здесь. Эти вопросы рассматриваются в третьей и четвертой главах моей книги "Практическое руководство по разработке приложений на Flutter", где они представлены как ключевые моменты всего учебника. Эта информация не устареет даже при переходе на новые версии Flutter.

А это уже реклама?

Flutter — это фреймворк со своими недостатками

И последнее, о недостатках Flutter. Никакой фреймворк не идеален, если бы он был совершенен, наша конкурентоспособность была бы ниже.

Именно поэтому разработка для Android и iOS была очень популярна вначале, но теперь рынок клиентских приложений становится более рациональным. Этот сектор стал намного зрелее, и потому стало больше конкуренции. Действительно, я всегда считал, что использование фреймворков само по себе не приносит особой ценности, а решение проблем, возникающих при использовании этих фреймворков, является нашей уникальной ценностью.

У Flutter тоже есть свои проблемы, такие как:- Проблемы с WebView: Уникальная система UI Flutter требует специального подхода для интеграции компонентов, таких как WebView, MapView. Это приводит к различным проблемам производительности, работы клавиатуры, полей ввода и других технических вопросов после интеграции. Подробнее можно прочитать здесь: «Глубокий анализ Hybrid Composition» и «Проблемы с Android PlatformView и клавиатурой».- Обработка и загрузка изображений: Способность Flutter обрабатывать и загружать изображения явно недостаточна, особенно когда дело доходит до загрузки одного большого изображения или отображения множества изображений. Flutter часто сталкивается с проблемами переполнения памяти и частичного переполнения GPU. Эти проблемы сложны в решении, и если требуется использование native платформы для решения, это требует использования внешних текстур, что увеличивает стоимость поддержки.

  • Гибридное развитие: Из-за того, что контроллеры и стек страниц Flutter работают вне native платформы, гибридное развитие может повысить затраты на обслуживание. Сейчас наиболее используемые flutter_boost и flutter_thrio не полностью решают основные проблемы гибридного развития, поэтому Flutter также испытывает трудности в этом отношении.

Изображение

Однако фактические вопросы, связанные с Flutter, зачастую имеют мало отношения к самому фреймворку, например:

  • «При запуске flutter doctor процесс зависает»
  • «При запуске flutter run происходит ошибка»
  • «При выполнении flutter pub get почему выдается сообщение о неправильной версии Dart?»
  • «При запуске Gradle возникают ошибки, такие как timeout»
  • «iOS невозможно запустить на реальном устройстве»
  • «Есть ли готовые компоненты типа xxx?»Честно говоря, эти вопросы скорее всего связаны с логами, документацией и поиском информации в интернете, чем с самим Flutter...

Изображение

Хотя Flutter имеет свои недостатки, но в целом он остаётся самым подходящим UI фреймворком для меня на данном этапе.### В конце

Долго не писал такого объёма материала, обычно людей, которые читают такие длинные статьи до конца, немного. Но надеюсь, что эта статья поможет вам более полно понять Flutter или направит вас в правильном направлении при обучении этому фреймворку. В заключение хочу процитировать слова одного известного специалиста:

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


Опубликовать ( 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