├── LICENSE ├── README.md └── README_EN.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Zahar Podyakov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Flutter Interview](https://github.com/p0dyakov/flutter_interview/assets/80569772/68dccc7f-b4f2-4eca-932a-8f9fe5559b5f) 2 | [ENGLISH VERSION](https://github.com/p0dyakov/flutter_interview/blob/main/README_EN.md) 3 | 4 | **Репозитории:** [Flutter Interview](https://github.com/p0dyakov/flutter_interview), [Flutter Roadmap](https://github.com/p0dyakov/flutter_roadmap), [Flutter Acrticles](https://github.com/p0dyakov/flutter_articles), [Flutter Best Packages](https://github.com/p0dyakov/flutter_best_packages), [Flutter Tools](https://github.com/p0dyakov/flutter_tools) 5 | 6 | 7 | 8 | - [Общие](#) 9 | * [ООП](#-1) 10 | * [SOLID](#solid) 11 | * [Git Flow](#git-flow) 12 | * [Структуры данных](#-) 13 | * [Императивное и декларативное программирование](#--1) 14 | * [Стек и куча](#--2) 15 | * [DAO, DTO, VO, BO](#dao-dto-vo-bo) 16 | * [DI и Service Locator](#di-service-locator) 17 | - [Dart](#dart) 18 | * [final и const](#final-const) 19 | * [JIT и AOT](#jit-aot) 20 | * [Hot Restart и Hot Reload](#hot-restart-hot-reload) 21 | * [HashCode](#hashcode) 22 | * [Extension](#extension) 23 | * [Mixin](#mixin) 24 | * [Sound Null Safety](#sound-null-safety) 25 | * [Система типов](#--3) 26 | * [Late](#late) 27 | * [Generics](#generics) 28 | * [Dart VM](#dart-vm) 29 | * [Зоны](#-2) 30 | * [Типы ошибок](#--4) 31 | * [Правила именования](#--5) 32 | * [Never](#never) 33 | * [Covariant](#covariant) 34 | * [Аннотации](#-3) 35 | * [int8, uint8, int16, uint16...](#int8-uint8-int16-uint16) 36 | * [Future](#future) 37 | * [Конструкторы Future](#-future) 38 | * [Await под капотом](#await-) 39 | * [Event Loop](#event-loop) 40 | * [Completer](#completer) 41 | * [Stream](#stream) 42 | * [Генераторы (sync* / async*) ](#-sync-async) 43 | * [Многопоточность в Dart и Flutter ](#-dart-flutter) 44 | * [Isolate](#isolate) 45 | * [Compute](#compute) 46 | * [Проблемы многопоточности](#--6) 47 | - [Flutter](#flutter) 48 | * [Stateless и Stateful виджеты](#stateless-stateful-) 49 | * [Жизненный цикл Stateful виджета](#-stateful-) 50 | * [BuildContext](#buildcontext) 51 | * [InheritedWidget](#inheritedwidget) 52 | * [Деревья](#-4) 53 | * [Widget](#widget) 54 | * [Element](#element) 55 | * [RenderObject](#renderobject) 56 | * [Виды виджетов](#--7) 57 | * [Виды элементов](#--8) 58 | * [Жизненный цикл Element-а](#-element-) 59 | * [GlobalKeys](#globalkeys) 60 | * [LocalKeys](#localkeys) 61 | * [Устройство Flutter под капотом ](#-flutter-) 62 | * [Модель выполнения во Flutter](#-flutter) 63 | * [CustomPaint](#custompaint) 64 | * [WidgetsFlutterBinding](#widgetsflutterbinding) 65 | * [Bindings](#bindings) 66 | * [Каналы платформы](#--9) 67 | * [Режимы сборки](#--10) 68 | * [Package и Plugin](#package-plugin) 69 | * [FFI Plugin](#ffi-plugin) 70 | * [Этапы анимации](#--11) 71 | * [Виды анимаций](#--12) 72 | * [Что такое Tween](#-tween) 73 | * [Tween анимации](#tween-) 74 | * [Построение кадра](#--13) 75 | * [Расчёт макета](#--14) 76 | * [BuildOwner](#buildowner) 77 | * [PipelineOwner](#pipelineowner) 78 | * [Garbage Collector](#garbage-collector) 79 | * [Task Runners](#task-runners) 80 | - [Архитектура](#-5) 81 | * [Архитектура](#-6) 82 | * [Чистая архитектура](#--15) 83 | * [Управление состоянием](#--16) 84 | * [Dependency Injection ](#dependency-injection) 85 | * [Архитектурные патерны ](#--17) 86 | * [Способы осуществления навигации](#--18) 87 | * [Базы данных](#--19) 88 | - [Тестирование](#-7) 89 | * [Виды тестов](#--20) 90 | * [TDD](#tdd) 91 | - [Паттерны разработки](#--21) 92 | 93 | 94 | 95 | 96 | ## Общие 97 | 98 | 99 | ### ООП 100 | `Объектно-ориентированное программирование` — это парадигма программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования. 101 | - `Абстракция` 102 | Моделирование взаимодействий сущностей в виде абстрактных классов и интерфейсов для представления системы 103 | - `Инкапсуляция` 104 | Объединение данных и методов, работающих с ними, в классе 105 | - `Наследование` 106 | Создания новых классов на основе существующих 107 | - `Полиморфизм` 108 | Использование объектов с одинаковым интерфейсом без информации о типе и внутренней структуре объекта 109 | 110 | [Подробнее](https://habr.com/ru/post/463125/) 111 | 112 | --- 113 | 114 | ### SOLID 115 | - `Single Responsibility Principle (Принцип единственной ответственности)` 116 | Класс должен отвечать только за что-то одно. 117 | - `Open-Closed Principle (Принцип открытости-закрытости)` 118 | Программные сущности должны быть открыты для расширения, но закрыты для модификации. 119 | - `Liskov Substitution Principle (Принцип подстановки Барбары Лисков)` 120 | Наследующий класс должен дополнять, а не замещать поведение базового класса. 121 | - `Interface Segregation Principle (Принцип разделения интерфейса)` 122 | Клиенты не должны имплементировать логику, которую они не используют. 123 | - `Dependency Inversion Principle (Принцип инверсии зависимостей)` 124 | Модули верхних уровней не должны зависеть от модулей нижних уровней. Классы и верхних, и нижних уровней должны зависеть от одних и тех же абстракций (при чём абстракции не должны знать о деталях). 125 | 126 | --- 127 | 128 | ### Git Flow 129 | Фича 130 | 1. `Начало новой фичи`. Создаём новую ветку `feature/future_name` из `develop` 131 | 2. `Завершение фичи`. Сливаем `feature/future_name` в `develop`, удаляем `feature/future_name` 132 | 3. `Начало релиза`. Создаём ветку релиза `release/vX.X.X`, ответляя от ветки `develop` 133 | 4. `Завершение релиза`. Ветка релиза `release/vX.X.X` сливается в `master`, релиз помечается тегом, ветка релиза сливается в `develop`, ветка релиза удаляется 134 | 135 | Фикс 136 | 1. `Начало исправления`. От ветки `master` создаём `hotfix/fix_name` 137 | 2. `Завершение исправления`. Из ветки `hotfix/fix_name` исправление сливается в `develop` и `master`, ветка фикса удаляется 138 | 139 | --- 140 | 141 | ### Структуры данных 142 | Структуры данных нужны для хранения данных в подходящем виде 143 | - `Массивы` 144 | - `Стеки` (*LIFO* - последний вошёл, первый вышел) 145 | - `Очереди` (*FIFO* - первый вошёл, первый вышел) 146 | - `Связные списки` 147 | - `Деревья` 148 | - `Графы` 149 | - `Хеш-таблицы` 150 | 151 | [Подробнее](https://habr.com/ru/company/alconost/blog/419685/) 152 | 153 | --- 154 | 155 | ### Императивное и декларативное программирование 156 | - `Императивный стиль` - описываем, **как** добиться желаемого результата 157 | - `Декларативный стиль` - описываем, **какой именно результат** нам нужен 158 | 159 | --- 160 | 161 | ### Стек и куча 162 | - `Стек` — это область оперативной памяти, в которой хранятся временные данные, таких как локальные переменные и адреса возврата функций. Объем памяти, выделенный под стек, ограничен. Стек работает в порядке LIFO 163 | - `Куча` — это область оперативной памяти, в которой хранятся данные, созданные во время выполнения программы. Куча используется для динамического выделения памяти для объектов, которые могут изменять размер во время выполнения программы. Размер кучи задаётся при запуске приложения, но, в отличие от стека, он ограничен лишь физически. Выделение памяти в куче происходит медленнее, чем в стеке. 164 | 165 | --- 166 | 167 | ### DAO, DTO, VO, BO 168 | - `DAO (Data Access Object, объект доступа к данным)` — абстрактный интерфейс к какому-либо типу базы данных или иному механизму хранения 169 | - `DTO (Data Transfer Object, объект переноса данных)` - это объект для передачи данных (объектов без поведения) между слоями 170 | - `VO (Value Object, объект-значение)` ⎼ это объект без специальных методов, имеющий набор свойств (полей) примитивных типов данных или тоже Value object 171 | - `BO (Business Object, объект бизнеса)` - это объект, который представляют некую сущность из определенного «домена», то есть отрасли, для которой разработано приложение 172 | 173 | --- 174 | 175 | ### DI и Service Locator 176 | - `DI` - передача зависимостей класса через параметры конструктора 177 | - `Service Locator` - синглтон / класс с набором статических методов 178 | 179 | Доступ к `Service Locator` может производиться из любого место в коде. В этом заключается его основной минус 180 | 181 | 182 | ## Dart 183 | 184 | ### final и const 185 | - `final` вычисляется в runtime-е. Константно только значение экземпляра. При использовании экземпляра final в памяти выделяется новая область памяти, даже если значение объекта будет идентично. 186 | - `const` вычисляется во время компиляции. Константно не только значение, но и сам экземпляр. При использовании const переменной новая область памяти не выделяется, а используется ссылка на уже существующий экземпляр 187 | 188 | --- 189 | 190 | ### JIT и AOT 191 | - `Just-in-time (JIT) компиляция` - это вид компиляции, который выполняется непосредственно во время работы программы, что существенно ускоряет цикл разработки. Но стоит учитывать, что программа может притормаживать и выполняться медленнее 192 | - `Ahead-of-time (AOT) компиляция` - это вид компиляции, который полностью выполняется перед запуском программы. Код на Dart преобразуется в нативный машинный код, который затем упаковывается в бинарный файл с расширением `.so` для `Android` или `.dylib` для `iOS`. `AOT` Занимает больше времени, чем `JIT`, но в результате программа работает куда быстрее. 193 | 194 | --- 195 | 196 | ### Hot Restart и Hot Reload 197 | - `Hot Reload` загружает изменения в `Dart VM` и ребилдит дерево виджетов, сохраняя состояние. Не перезапускает `main()` и `initState()` 198 | - `Hot Restart` загружает изменения в `Dart VM` и перезагружает всё приложение. Перезапускает `main()` и `initState()`. Состояние не сохраняется 199 | 200 | --- 201 | 202 | ### HashCode 203 | `Хэш-код` - геттер, у любого объекта, который возвращает `int`. Нужен при сохранении объекта в `map` или `set`. Хэш-коды должны быть одинаковыми для объектов, которые равны друг другу в соответствии с оператором == 204 | `int get hashCode => Object.hash(runtimeType, ..., ...);` 205 | 206 | --- 207 | 208 | ### Extension 209 | `Extension` — это синтаксический сахар, который позволяет расширить существующий класс (добавить методы, операторы, сеттеры и геттеры) 210 | 211 | --- 212 | 213 | ### Mixin 214 | `Миксин` - это механизм множественного наследования, который позволяет классам использовать функциональность других классов без явного наследования. 215 | 216 | Миксины в Dart определяются ключевым словом `mixin`. Они могут содержать методы, поля и геттеры/сеттеры, но не могут иметь конструкторов. Вместо этого, миксины инициализируются автоматически, когда они применяются к классу. Для использования миксинов применяется оператор `with` 217 | 218 | Если у миксинов будет метод с одинаковым названием, то останется реализация, которая указана в последнем миксине. Так как миксины будут переопределять этот метод 219 | 220 | --- 221 | 222 | ### Sound Null Safety 223 | `Sound Null Safety` – это дополнение к языку Dart, которое усиливает систему типов, отделяя типы, допускающие значение `Null`, от типов, не допускающих значения `Null`. Это позволяет разработчикам предотвращать ошибки, связанные с `Null`. 224 | 225 | --- 226 | 227 | ### Система типов 228 |

229 | 230 |

231 | С появлением null safety в Dart, иерархия классов и интерфейсов была изменена для учета новых требований по безопасности типов. Вот основные изменения: 232 | 233 | 1. **Добавление non-nullable типов**: 234 | - Non-nullable типы обозначают, что значение не может быть null. 235 | - Все существующие типы были разделены на non-nullable и nullable версии. Например, `int` стал `int` (non-nullable) и `int?` (nullable) 236 | 237 | 2. **Новый корень иерархии - "Object?"**: 238 | - Введен новый корневой класс `Object?`, который может быть null. В предыдущих версиях Dart, корневым классом был `Object` 239 | 240 | 3. **Изменения в иерархии ошибок**: 241 | - Введен новый класс `NullThrownError`, который представляет собой ошибку, возникающую при попытке выбросить `null` исключение 242 | 243 | 4. **`late` и `required`**: 244 | - Введены ключевые слова `late` и `required` для обозначения переменных, которые могут быть инициализированы позднее и обязательно должны быть проинициализированы при объявлении, соответственно. 245 | 246 | --- 247 | 248 | ### Late 249 | `Late` - это ключевое слово в dart, которое позволяет объявить non-nullable переменную и при этом не установить для нее значение. Значение инициализируется только тогда, когда мы к нему обращаемся 250 | 251 | --- 252 | 253 | ### Generics 254 | `Generics` - это параметризованные типы. Они позволяют программе уйти от жесткой привязки к определенным типам, определить функционал так, чтобы он мог использовать данные любых типов и обеспечить их безопасность. Так же обобщения снижают повторяемость кода, дают вам возможность предоставить единый интерфейс и реализацию для многих типов. 255 | 256 | --- 257 | 258 | ### Dart VM 259 | `Dart VM (Dart virtual machine)` - среда выполнения Dart 260 | 261 | Компоненты: 262 | - `Среда исполнения` 263 | - `Сборщик мусора` 264 | - `Основные библиотеки и нативные методы` 265 | - `Система отладка` 266 | - `Профилировщик` 267 | - `Симулятор ARM архитектуры` 268 | 269 | --- 270 | 271 | ### Зоны 272 | Зона - это механизм, который позволяет управлять и обрабатывать ошибки и другие события, происходящие в определенных областях кода. 273 | 274 | 1. Защита вашего приложения от завершения из-за необработанного исключения 275 | 2. Ассоциирование данных, известных как `zone-local values`, с отдельными зонами 276 | 3. Переопределение ограниченного набора методов, таких как print() и scheduleMicrotask(), внутри части или всего кода 277 | 4. Выполнение операции каждый раз, когда код входит или выходит из зоны. Эти операции могут включать в себя запуск или остановку таймера или сохранение stacktrace-а 278 | 279 | --- 280 | 281 | ### Типы ошибок 282 | `Exception` - это общий класс для исключений, которые обычно возникают из-за ошибок в программе, и их можно обработать и восстановиться от них: 283 | - DeferredLoadException 284 | - FormatException 285 | - IntegerDivisionByZeroException (помечен как устаревший) 286 | - IOException 287 | - FileSystemException 288 | - PathNotFoundException 289 | - HttpException 290 | - RedirectException 291 | - ProcessException 292 | - SignalException 293 | - SocketException 294 | - StdinException 295 | - StdoutException 296 | - TlsException 297 | - CertificateException 298 | - HandshakeException 299 | - WebSocketException 300 | - IsolateSpawnException 301 | - TimeoutException 302 | - NullRejectionException 303 | 304 | `Error` - это класс для ошибок, которые обычно не могут быть восстановлены, и они указывают на серьезные проблемы в программе или системе: 305 | - OSError 306 | - ArgumentError 307 | - IndexError 308 | - RangeError 309 | - AssertionError 310 | - AsyncError 311 | - ConcurrentModificationError 312 | - JsonUnsupportedObjectError 313 | - JsonCyclicError 314 | - NoSuchMethodError 315 | - OutOfMemoryError 316 | - RemoteError 317 | - StackOverflowError 318 | - StateError 319 | - TypeError 320 | - UnimplementedError 321 | - UnsupportedError 322 | 323 | --- 324 | 325 | ### Правила именования 326 | - Переменные и константы - `lowerCamelCase` 327 | - Классы, миксины, enum-ы - `UpperCamelCase` 328 | - Файлы - `snake_case` 329 | 330 | --- 331 | 332 | ### Never 333 | `Never` - это тип, означающий, что ни один тип не разрешен и `Never` сам по себе не может быть создан. Используется как возвращаемый тип при гарантированной ошибке. 334 | 335 | --- 336 | 337 | ### Covariant 338 | `Covariant` - это ключевое слово в dart, которое указывает на то, что тип возвращаемого значения может быть изменен на более узкий тип в подклассе. 339 | 340 | --- 341 | 342 | ### Аннотации 343 | `Аннотации` — это синтаксические метаданные, которые могут быть добавлены к коду. Другими словами, это возможность добавить дополнительную информацию к любому компоненту кода, например, к классу или методу. Аннотации всегда начинаются с символа `@` (`@override`, `@required`). Любой класс может служить аннотацией, если в нем определен const конструктор. 344 | 345 | --- 346 | 347 | ### int8, uint8, int16, uint16... 348 | |Спецификатор|Общий эквивалент|Байты|Минимальное значение|Максимальное значение| 349 | |--|--|--|--|--| 350 | |int8|signed char|1|-128|127| 351 | |uint8|unsigned char|1|0|255| 352 | |int16|short|2|-32,768|32,767| 353 | |uint16|unsigned short|2|0|65,535| 354 | |int32|long|4|-2,147,483,648|2,147,483,647| 355 | |uint32|unsigned long|4|0|4,294,967,295| 356 | |int64|long long|8|-9,223,372,036,854,775,808|9,223,372,036,854,775,807| 357 | |uint64|unsigned long long|8|0|18,446,744,073,709,551,615| 358 | 359 | --- 360 | 361 | ### Future 362 | `Future` - это обёртка над результатом выполнения асинхронной операции. Код Future НЕ выполняется параллельно, а выполняется в последовательности, определяемой Event Loop. 363 | Состояния Future: 364 | - Uncompleted - операция не завершена 365 | - Completed with Result - операция завершена успешно 366 | - Completed with Error - операция завершена с ошибкой 367 | 368 | --- 369 | 370 | ### Конструкторы Future 371 | - `Future(FutureOr computation())`: создает объект future, который с помощью метода Timer.run запускает функцию computation асинхронно и возвращает ее результат. 372 | - `FutureOr`: указывает, что функция computation должна возвращать либо объект Future либо объект типа T. Например, чтобы получить объект Future, функция computation должна возвращать либо объект Future, либо объект int 373 | - `Future.delayed(Duration duration, [FutureOr computation()])`: создает объект Future, который запускается после временной задержки, указанной через первый параметр Duration. Второй необязательный параметр указывает на функцию, которая запускается после этой задержки. 374 | - `Future.error(Object error, [StackTrace stackTrace])`: создает объект Future, который содержит информацию о возникшей ошибке. 375 | - `Future.microtask(FutureOr computation())`: создает объект Future, который с помощью функции scheduleMicrotask запускает функцию computation асинхронно и возвращает ее результат. 376 | - `Future.sync(FutureOr computation())`: создает объект Future, который содержит результат немедленно вызываемой функции computation. 377 | - `Future.value([FutureOr value])`: создает объект Future, который содержит значение value. 378 | 379 | --- 380 | 381 | ### Await под капотом 382 | Под капотом `await` перемещает весь последующий код в `then` у `Future`, которую мы дожидаемся 383 | 384 | --- 385 | 386 | ### Event Loop 387 | `Event Loop` - вечный цикл, выполняющий все поступающие в изолят задачи. 388 | В нём есть две FIFO очереди задач: 389 | 390 | `Очередь MicroTask` 391 | Используется для очень коротких действий, которые должны быть выполнены асинхронно, сразу после завершения какой-либо инструкции перед тем, как передать управление обратно Event Loop. Очередь MicroTask имеет приоритет перед очередью Event 392 | 393 | `Очередь Event` 394 | Используется для планирования операций, которые получают результат от внешних событий (операции ввода/вывода, жесты, рисование, таймеры, потоки) 395 | 396 | --- 397 | 398 | ### Completer 399 | `Completer` позволяет поставлять Future, отправлять событие о выполнении или событие об ошибке. Это может быть полезно, когда нужно сделать цепочку Future и вернуть результат. 400 | 401 | --- 402 | 403 | ### Stream 404 | `Stream` - это последовательность асинхронных событий. Stream сообщает вам, что есть событие и когда оно будет готово 405 | - `Single subscription` - это вид потока, при котором может быть только один подписчик. 406 | - `Broadcast` - это вид потока, при котором может быть много подписчиков. При этом Broadcast стримы отдают свои данные вне зависимости от того, подписан ли кто-нибудь на них или нет. Подписчики стрима получают события только с момента подписки, а не с момента старта жизни стрима 407 | 408 | --- 409 | 410 | ### Генераторы (sync* / async*) 411 | `Генератор` это ключевое слово, которое позволяет создавать последовательность значений с помощью `yield` 412 | - *sync** - это синхронный генератор. Возвращает `Iterable` 413 | - *async** - это aсинхронный генератор. Возвращает `Stream` 414 | 415 | --- 416 | 417 | ### Многопоточность в Dart и Flutter 418 | `Dart` — однопоточный язык программирования. Он исполняет одновременно одну инструкцию. Но при этом мы можем запустить код в отдельном поток с помощью `Isolate` 419 | 420 | --- 421 | 422 | ### Isolate 423 | `Isolate` - это легковесный процесс (поток исполнения), который выполняется параллельно с другими потоками и процессами в приложении. Каждый `Isolate` в Dart имеет свой собственный экземпляр виртуальной машины Dart, собственную память и управляется с помощью своего `Event Loop`. 424 | 425 | --- 426 | 427 | ### Compute 428 | `Compute` - это функция, которая создаёт изолят и запускает переданный код. 429 | 430 | --- 431 | 432 | ### Проблемы многопоточности 433 | 434 | - `Deadlock` — каждый из потоков ожидают событий, которые могут предоставить другие потоки 435 | - `Race conditions` — проявление недетерминизма исполнителя программы при различном относительном порядке исполнения команд в различных потоках 436 | - `Lock Contention` — основное время потока проводится не в исполнении полезной работы, а в ожидании блокированного другим потоком ресурса 437 | - `Live Lock` — поток захватывает ресурс, но после того, как убедится, что завершить работу не может, освобождает ресурс, аннулируя результаты 438 | 439 | 440 | ## Flutter 441 | 442 | 443 | ### Stateless и Stateful виджеты 444 | - `StatelessWidget` - это виджет, который не имеет состояния, в процессе работы приложения не изменяет своих свойств. Они могут изменяться лишь посредством внешних событий, которые возникают в родительских виджетах 445 | - `StatefulWidget` - это виджет, который хранит состояние, в процессе работы приложения он может его изменять динамически с помощью `setState()`. 446 | 447 | --- 448 | 449 | ### Жизненный цикл Stateful виджета 450 | 1. `createState()` вызывается единожды и создает изменяемое состояние для этого виджета в заданном месте в дереве 451 | 2. `mounted is true` 452 | 3. `initState()` вызывается единожды при инициализации 453 | 4. `didChangeDependencies()` вызывается единожды после инициализации и далее при уведомлениях от Inhherited-виджетов вверху по дереву, от которых зависит виджет 454 | 5. `build()` вызывается каждый раз при перерисовке 455 | 6. `didUpdateWidget(Widget oldWidget)` вызывается каждый раз при обновлении конфигурации виджета 456 | 7. `setState()` вызывается императивно для перерисовки 457 | 8. `deactivate()` вызывается, когда ранее активный элемент перемещается в список неактивных элементов, при этом удаляясь из дерева 458 | 9. `dispose()` вызывается, когда этот объект удаляется из дерева **навсегда** 459 | 10. `mounted is false` 460 | 461 | --- 462 | 463 | ### BuildContext 464 | `BuildContext` - это интерфейс, который имплементирует `Element`. 465 | 466 | `BuildContext` может быть полезен, когда нужно: 467 | - Получить ссылку на объект `RenderObject`, соответствующий виджету (или, если виджет не является Renderer, то виджету-потомку) 468 | - Получить размер `RenderObject` 469 | - Обратиться к дереву и получить ближайший родительский `InheritedWidget`. Это используется фактически всеми виджетами, которые обычно реализуют метод of (например, `MediaQuery.of(context)`, `Theme.of(context)` и т.д.) 470 | 471 | --- 472 | 473 | ### InheritedWidget 474 | `InheritedWidget` — это виджет, который предоставляет своим потомкам возможность взаимодействовать с данными, хранящимися в нём. Решает проблему с передачей данных через конструкторы. Может уведомлять виджетов внизу по дереву об изменениях в собственных данных, тем самым провоцируя их перерисовку. 475 | Для получения Inherited виджета необходимо вызвать `context.dependOnInheritedWidgetOfExactType()` в `didChangeDependencies()` 476 | 477 | *Сложность у операции получения InheritedWidget - O(1). Такая скорость достигается за счёт того, что Inherited виджеты хранятся в виде хэш-таблицы в `Element`-е* 478 | 479 | --- 480 | 481 | ### Деревья 482 | ![](https://docs.flutter.dev/assets/images/docs/arch-overview/trees.png) 483 | - `Widget Tree` состоит из `Widget`, которые используются для описания пользовательского интерфейса 484 | - `Element Tree` состоит из `Element`, которые управляют жизненым циклом виджета и связывают виджеты и объекты рендеринга. 485 | - `Render Tree` состоит из `RenderObject`, которые используются для определения размеров, положения, геометрии, определения зон экрана, на которые могут повлиять жесты 486 | 487 | [Подробнее](https://habr.com/ru/company/surfstudio/blog/533210/) 488 | 489 | --- 490 | 491 | ### Widget 492 | `Widget` - это иммутабельное описание части пользовательского интерфейса. Виджет связан с элементом, который управляет рендерингом. Виджеты образуют сруктуру, а не дерево 493 | 494 | --- 495 | 496 | ### Element 497 | `Element` - это мутабельное представление виджета в определенном месте дерева. Управляют жизненым циклом, связывают виджеты и объекты рендеринга. 498 | 499 | --- 500 | 501 | ### RenderObject 502 | `RenderObject` - это мутабельный объект дерева визуализации. У него есть родительский объект, а также поле с данными, которое родительский объект использует для хранения специфичной информации, касающейся самого этого объекта, например, его позицию. Данный объект отвечает за отрисовку, учёт размеров и ограничений, прослушивание и обработку нажатий. При необходимости перерисовки помечается как `dirty`. Перерисовывается, используя свой метод `layer` 503 | 504 | --- 505 | 506 | ### Виды виджетов 507 | `Proxy` - это виджеты, которые хранят некоторую информацию и делают её доступной для потомков. Эти виджеты не принимают непосредственного участия в формировании пользовательского интерфейса, но используются для получения информации, которую они могут предоставить. 508 | - `InheritedWidget` 509 | - `ParentDataWidget` (`LayoutId`, `Flexible`, `KeepAlive` и т.д.) 510 | - `NotificationListener` 511 | 512 | `Renderer` - это виджеты, которые имеют непосредственное отношение к компоновке экрана, поскольку они определяют размеры, положение, отрисовку 513 | - `Row` 514 | - `Column` 515 | - `Stack` 516 | - `Padding` 517 | - `Align` 518 | - `Opacity` 519 | 520 | `Component` - это виджеты, которые предоставляют непосредственно не окончательную информацию, связанную с размерами, позициями, внешним видом, а скорее данные (или подсказки), которые будут использоваться для получения той самой финальной информации 521 | - `RaisedButton` 522 | - `Scaffold` 523 | - `Text` 524 | - `GestureDetector` 525 | - `Container` 526 | 527 | --- 528 | 529 | ### Виды элементов 530 | ![image](https://user-images.githubusercontent.com/80569772/205450564-87d6c2d0-a994-4d1d-bbaa-2c8f7fb07385.png) 531 | `ComponentElement` - компоновочный элемент, который явно не содержит логику рисования/отображения. Есть метод `build()`, который возвращает виджет. Образуется только при создании виджетов `StatelessWidget`, `StatefulWidget`, `InheritedWidget`. 532 | - `ProxyElement` 533 | - `StatelessElement` 534 | - `StatefulElement` 535 | 536 | `RenderObjectElement` - отображающий элемент, явно участвующий в рисовании компонентов на экране. Содержит `renderObject` и наследуется от класса `Element`. Образуется при создании виджетов `Padding`, `Column`, `Row`, `Center` и др. 537 | - `LeafRenderObjectElement` 538 | - `ListWheelElement` 539 | - `MultiChildRenderObjectElement` 540 | - `RootRenderObjectElement` 541 | - `SingleChildRenderObjectElement` 542 | - `SliverMultiBoxAdaptorElement` 543 | - `SlottedRenderObjectElement` 544 | 545 | --- 546 | 547 | ### Жизненный цикл Element-а 548 | 1. Элемент создаётся посредством вызова метода `Widget.createElement` и конфигурируется экземпляром виджета, у которого был вызван метод. 549 | 2. С помощью метода `mount` созданный элемент добавляется в заданную позицию родительского элемента. При вызове данного метода также ассоциируются дочерние виджеты и элементам сопоставляются объекты дерева рендеринга. 550 | 3. Виджет становится активным и должен появиться на экране. 551 | 4. В случае изменения виджета, связанного с элементом (например, если родительский элемент изменился), есть несколько вариантов развития событий. Если новый виджет имеет такой же `runtimeType` и `key`, то элемент связывается с ним. В противном случае, текущий элемент удаляется из дерева, а для нового виджета создаётся и ассоциируется с ним новый элемент. 552 | 5. В случае, если родительский элемент решит удалить дочерний элемент, или промежуточный между ними, это приведет к удалению объекта рендеринга и переместит данный элемент в список неактивных, что приведет к деактивации элемента. 553 | 6. Когда элемент считается неактивным, он не находится на экране. Элемент может находиться в неактивном состоянии только до конца текущего фрейма, если за это время он остается неактивным, он демонтируется, после этого считается несуществующим и больше не будет включен в дерево. 554 | 7. При повторном включении в дерево элементов, например, если элемент или его предки имеют глобальный ключ, он будет удален из списка неактивных элементов, будет вызван метод `activate`, и рендер объект, сопоставленный данному элементу, снова будет встроен в дерево рендеринга. Это означает, что элемент должен снова появиться на экране. 555 | 556 | --- 557 | 558 | ### GlobalKeys 559 | `GlobalKeys` - это ключи, которые предоставляют доступ к виджетам. Для виджетов с отслеживанием состояния глобальные ключи также предоставляют доступ к состоянию. Позволяют виджетам менять родителей в любом месте приложения без потери состояния. Должны быть уникальны для всего приложения. 560 | 561 | --- 562 | 563 | ### LocalKeys 564 | `LocalKeys` - это ключи, которые нужны для идентификации виджетов в коллекции с одинаковыми значениеми должны быть уникальными среди виджетов с одним и тем же родительским виджетом. Могут использоваться для тестов: 565 | - `ValueKey` - это ключ, который использует значение определенного типа для идентификации самого себя. Переопределяет оператор сравнения. Если value одниковое, то ключи одинаковые 566 | - `UniqueKey` - это ключ, который равен только самому себе 567 | - `ObjectKey` - это ключ, который используется для привязки идентификатора виджета к идентификатору объекта, используемого для создания этого виджета 568 | 569 | --- 570 | 571 | ### Устройство Flutter под капотом 572 | ![image](https://user-images.githubusercontent.com/80569772/203052487-937d5923-9571-4752-9762-f0d6637b675e.png) 573 | 574 | `Уровень фреймворка` — всё, с чем мы работаем в момент написания приложения, и все служебные классы, позволяющие взаимодействовать написанному нами с уровнем движка. Всё, относящееся к данному уровню написано на Dart. `Flutter Framework` взаимодействует с `Flutter Engine` через слой абстракции, называемый `Window` 575 | 576 | `Уровень движка` — более низкий уровень, чем уровень фреймворка, содержит классы и библиотеки, позволяющие работать уровню фреймворка. В том числе `виртуальная машина Dart`, `Skia` и тд. 577 | 578 | `Уровень платформы` — специфичные механизмы, относящиеся к конкретной платформе запуска. 579 | 580 | `Flutter Engine` уведомляет `Flutter Framework`, когда: 581 | - Событие, представляющее интерес, происходит на уровне устройства (изменение ориентации, изменение настроек, проблема с памятью, состояние работы приложения…) 582 | - Какое-то событие происходит на уровне стекла (жест) 583 | - Канал платформы отправляет некоторые данные 584 | - Но также и в основном, когда Flutter Engine готов к рендерингу нового кадра 585 | 586 | --- 587 | 588 | ### Модель выполнения во Flutter 589 | 1. Создается и запускается новый процесс — `Thread (Isolate)`. Это единственный процесс, в котором будет выполняться ваше приложение. 590 | 2. Инициализируются две очереди с `MicroTask` и `Event`, тип очередей `FIFO` (прим.: first in first out, т.е. сообщение, пришедшие раньше, будут раньше обработаны) 591 | 3. Исполняется функция `main()` 592 | 4. Запускается `Event Loop`. Он управлет порядком исполнения вашего кода, в зависимости от содержимого двух очередей: `MicroTask` и `Event`. Представляет собой "бесконечный" цикл. 593 | 5. `Event Loop` с определённой частотой проверяет `MicroTask` и `Event`. Если есть что-то в `MicroTask`, то оно выполняется перед очередью `Event`. 594 | 595 | --- 596 | 597 | ### CustomPaint 598 | `CustomPaint` - это класс, который создает «холст» для рисования. В методе `paint` в качестве аргументов поступает `canvas`, который позволяет рисовать различные фигуры 599 | 600 | --- 601 | 602 | ### WidgetsFlutterBinding 603 | `WidgetsFlutterBinding` — конкретная реализация привязки приложений на основе инфраструктуры виджетов. По сути своей — это клей, соединяющий фреймворк и движок Flutter. `WidgetsFlutterBinding` состоит из множества связей: `GestureBinding`, `ServicesBinding`, `SchedulerBinding`, `PaintingBinding`, `SemanticsBinding`, `RendererBinding`, `WidgetsBinding`. 604 | 605 | Метод `scheduleAttachRootWidget` является отложенной реализацией `attachRootWidget`. Принадлежит данный метод `WidgetsBinding`. В описании к нему сказано, что он присоединяет переданный виджет к `renderViewElement` — корневому элементу дерева элементов. 606 | 607 | Метод `scheduleWarmUpFrame` принадлежит `SchedulerBinding` и используется для того, чтобы запланировать запуск кадра как можно скорее, не ожидая системного сигнала `Vsync`. 608 | 609 | --- 610 | 611 | ### Bindings 612 | ![image](https://user-images.githubusercontent.com/80569772/203303949-aadb037a-c818-4f63-8ad8-67c3812a96ad.png) 613 | 614 | `Bindings` - это классы для обмена данными между `Flutter Framework` и `Flutter Engine`. Каждая привязка отвечает за обработку набора конкретных задач, действий, событий, сгруппированных по области деятельности. 615 | 616 | `BaseBinding` — базовый абстрактный класс, давайте тогда рассмотрим конкретные реализации биндингов. Среди них мы увидим: 617 | 618 | `ServicesBinding` отвечает за перенаправление сообщений от текущей платформы в обработчик данных сообщений (`BinaryMessenger`); 619 | 620 | `PaintingBinding` отвечает за связь с библиотекой отрисовки. 621 | 622 | `RenderBinding` отвечает за связь между деревом рендеринга и движком Flutter. 623 | 624 | `WidgetBinding` отвечает за связь между деревом виджетов и движком Flutter. 625 | 626 | `SchedulerBinding` — планировщик очередных задач, таких как: 627 | - вызовы приходящих колбеков, которые инициирует система в `Window.onBeginFrame` — например события тикеров и контроллеров анимаций; 628 | - вызовы непрерывных колбеков, которые инициирует система `Window.onDrawFrame`, например, события для обновления системы отображения после того, как отработают приходящие колбеки; 629 | - посткадровые колбеки, которые вызываются после непрерывных колбеков, перед возвратом из `Window.onDrawFrame`; 630 | - задачи не связанные с рендерингом, которые должны быть выполнены между кадрами. 631 | 632 | `SemanticsBinding` отвечает за связь слоя семантики и движком Flutter. 633 | 634 | `GestureBinding` отвечает за работу с подсистемой жестов. 635 | 636 | --- 637 | 638 | ### Каналы платформы 639 | 640 | ![image](https://user-images.githubusercontent.com/80569772/202891758-b7cc7db9-3b4c-4ce3-9f91-37f9a1a614a1.png) 641 | **(!)** Платформенные взаимодействия возможны только в главном изоляте. Этот тот изолят, который создается при запуске вашего приложения. 642 | 643 | `Канал платформы` — это двусторонний канал связи между кодом на dart и нативом, который объединяет имя канала и кодек для кодирования сообщений в двоичную форму и обратно. Вызовы асинхронны. Каждый канал должен иметь уникальный идентификатор. 644 | 645 | `Каналы сообщений` - это каналы платформы, предназначенные для обмена сообщениями между нативным кодом и flutter-приложением. 646 | `Кодеки сообщений`: 647 | - `BinaryCodec` Реализуя сопоставление идентификаторов в байтовых буферах, этот кодек позволяет вам наслаждаться удобством объектов канала в тех случаях, когда вам не требуется кодирование/декодирование. Каналы сообщений Dart с этим кодеком имеют тип BasicMessageChannel. 648 | - `JSONMessageCodec` Работает с «JSON-подобными» значениями (строки, числа, логические значения, null, списки этих значений и мапы строка-ключ с этими данными). Списки и мапы неоднородны и могут быть вложены друг в друга. Во время кодирования значения преобразуются в строки JSON, а затем в байты с использованием UTF-8. Каналы сообщений Dart имеют тип BasicMessageChannel с этим кодеком. 649 | - `StandardMessageCodec` Работает с несколько более обобщенными значениями, чем кодек JSON, поддерживая также однородные буферы данных (UInt8List, Int32List, Int64List, Float64List) и мапы с нестроковыми ключами. Обработка чисел отличается от JSON тем, что целые числа Dart поступают на платформу как 32- или 64-битные целые числа со знаком, в зависимости от величины никогда как числа с плавающей запятой. Значения кодируются в специальном, достаточно компактном и расширяемом двоичном формате. Стандартный кодек предназначен для выбора по умолчанию для канала связи во Flutter. Что касается JSON, каналы сообщений Dart, созданные с использованием стандартного кодека, имеют тип BasicMessageChannel. 650 | 651 | `Каналы методов` — это каналы платформы, предназначенные для вызова нативного кода из flutter-приложения. 652 | `Кодеки методов`: 653 | - `StandardMethodCodec` делегирует кодирование значений полезной нагрузки (payload) в `StandardMessageCodec`. Поскольку последний является расширяемым, то же самое можно сказать и о первом. 654 | - `JSONMethodCodec` делегирует кодирование значений полезной нагрузки (payload) в `JSONMessageCodec`. 655 | 656 | `Каналы событий` — это специализированные каналы платформы, предназначенные для использования в случае представления событий платформы Flutter в виде потока Dart. Работает как обычный `Stream` 657 | 658 | [Подробнее](https://habr.com/ru/post/666272/) 659 | 660 | --- 661 | 662 | ### Режимы сборки 663 | - `Debug` (`JIT`) для разработки 664 | - `Release` (`AOT`) для публикации приложения 665 | - `Profile` (`AOT`) для анализа производительности 666 | 667 | --- 668 | 669 | ### Package и Plugin 670 | - `Package` написан только на dart 671 | - `Plugin` использует dart и специфичный код для платформы 672 | 673 | --- 674 | 675 | ### FFI Plugin 676 | - `FFI Plugin` - плагин, в котором для написания специфичных платформенных частей используется [Dart FFI](https://dart.dev/guides/libraries/c-interop). Позволяет запустить код на C / C++ 677 | 678 | --- 679 | 680 | ### Этапы анимации 681 | - `Ticker` просит `SchedulerBinding` зарегистрировать обратный вызов и сообщить `Flutter Engine`, что надо разбудить его, когда появится новый обратный вызов. 682 | - Когда `Flutter Engine` готов, он вызывает `SchedulerBinding` через запрос `onBeginFrame`. 683 | - `SchedulerBinding` обращается к списку обратных вызовов `ticker` и выполняет каждый из них. 684 | - Каждый `tick` перехватывается "заинтересованным" контроллером для его обработки. 685 | - Если анимация завершена, то `ticker` "отключён", иначе `ticker` запрашивает `SchedulerBinding` для планирования нового обратного вызова. 686 | - ... 687 | 688 | --- 689 | 690 | ### Виды анимаций 691 | - `Tween animation`. Начало, конец, время, скорость заранее определенно 692 | - `Physics-based animation`. Имитируют реальное поведение 693 | 694 | --- 695 | 696 | ### Что такое Tween 697 | `Tween` - это объект, который описывает между какими значениями анимируется виджет и отвечает за вычисление текущего значения анимации 698 | 699 | --- 700 | 701 | ### Tween анимации 702 | - `Implicit Animations` - это набор `Implicitly Animated Widgets`, которые анимируются самостоятельно при их перестройке с новыми аргументами. (`AnimatedAlign`, `AnimatedContainer`, `AnimatedPadding` и т.д.) 703 | - `Explicit Animations` - это набор элементов управления анимационными эффектами. Предоставляют куда больше контроля над анимацией, чем `Implicit Animations`. Для использования необходимо подмешать к стейту вашего виджета `SingleTickerProviderStateMixin` / `TickerProviderStateMixin`, создать `AnimationController` и зависящие от него `Animation`, передать анимацию в `Transition Widget` (`AlignTransition`, `DecoratedBoxTransition`, `SizeTransition` и т.д.) 704 | `SingleTickerProviderStateMixin` / `TickerProviderStateMixin` создает `Ticker` 705 | `Ticker` вызывает callback на каждый фрейм анимации 706 | `AnimationController` пределяет все фреймы анимации - управляет анимацией (forward, reverse, repeat, stop, reset и т.д.) 707 | `Animation` отдает текущее значение анимации, а также позволяет подписаться на обновления значения/статуса анимации 708 | 709 | --- 710 | 711 | ### Построение кадра 712 | 1. Некоторые внешние события приводят к необходимости обновления отображения. 713 | 2. `Schedule Frame` отправляется к `Flutter Engine` 714 | 3. Когда `Flutter Engine` готов приступить к обновлению рендеринга, он создает `Begin Frame` запрос 715 | 4. Этот `Begin Frame` запрос перехватывается `Flutter Framework`, который выполняет задачи, связанные в основном с `Tickers` (например, анимацию) 716 | 5. Эти задачи могут повторно создать запрос для более поздней отрисовки (пример: анимация не закончила своё выполнение, и для завершения ей потребуется получить еще один `Begin Frame` на более позднем этапе) 717 | 6. Далее `Flutter Engine` отправляет `Draw Frame`, который перехватывается `Flutter Framework`, который будет искать любые задачи, связанные с обновлением макета с точки зрения структуры и размера 718 | 7. После того, как все эти задачи выполнены, он переходит к задачам, связанным с обновлением макета с точки зрения отрисовки 719 | 8. Если на экране есть что-то, что нужно нарисовать, то новая сцена для визуализации отправляется в `Flutter Engine`, который обновит экран 720 | 9. Затем `Flutter Framework` выполняет все задачи, которые будут выполняться после завершения рендеринга (`PostFrame callbacks`), и любые другие последующие задачи, не связанные с рендерингом 721 | 10. … 722 | 723 | --- 724 | 725 | ### Расчёт макета 726 | - Ограничения спускаются вниз по дереву, от родителей к детям. 727 | - Размеры идут вверх по дереву от детей к родителям. 728 | - Родители устанавливают положение детей. 729 | 730 | --- 731 | 732 | ### BuildOwner 733 | `BuildOwner` — менеджер сборки и обновления дерева элементов. Он активно участвует в двух фазах — сборки и завершения сборки. Поскольку `BuildOwner` управляет процессом сборки дерева, в нем хранятся списки неактивных элементов и списки элементов, нуждающихся в обновлении. 734 | Методы: 735 | - `scheduleBuildFor` даёт возможность пометить элемент как нуждающийся в обновлении. 736 | - `lockState` защищает элемент от неправильного использования, утечек памяти и пометки на обновления в процессе уничтожения. 737 | - `buildScope` осуществляет пересборку дерева. Работает с элементами, которые помечены как нуждающиеся в обновлении. 738 | - `finalizeTree` завершает построение дерева. Удаляет неиспользуемые элементы и осуществляет дополнительные проверки в режиме отладки — в том числе на дублирование глобальных ключей. 739 | - `reassemble` обеспечивает работу механизма `HotReload`. Этот механизм позволяет не пересобирать проект при изменениях, а отправлять новую версию кода на `DartVM` и инициировать обновление дерева. 740 | 741 | --- 742 | 743 | ### PipelineOwner 744 | `PipelineOwner` — менеджер сборки, который занимается работой с деревом отображения. 745 | 746 | --- 747 | 748 | ### Garbage Collector 749 | `Garbage Collector` - это алгоритм, наблюдает за ссылками и очищает память с целью предотвращения её переполнения. 750 | 751 | **(!)** В процессе сборки мусора слой `Dart Framework` создает канал взаимодействия со слоем `Flutter Engine`, посредством которого узнает о моментах простоя приложения и отсутствия пользовательского взаимодействия. В эти моменты `Dart Framework` запускает процесс оптимизации памяти, что позволяет сократить влияния на пользовательский опыт и стабильность приложения. 752 | 753 | **Сборщик молодого мусора** 754 | ![image](https://user-images.githubusercontent.com/80569772/203299873-834979fb-a548-476a-8f69-8be50c7ebd64.png) 755 | 756 | Используемый объём памяти можно разделить на два пространства: активное и неактивное. Новые объекты располагаются в активной части, где по мере её заполнения, живые объекты переносятся из активной области памяти в неактивную, игнорируя мёртвые объекты. Затем неактивная половина становится активной. Этот процесс имеет цикличный характер. 757 | 758 | **Сборщик старого мусора (Parallel Marking and Concurrent Sweeping)** 759 | ![image](https://user-images.githubusercontent.com/80569772/203300039-95a12d39-d502-4064-8a31-e903407fa04a.png) 760 | 761 | 1. Осуществляется обход дерева объектов, используемые объекты помечаются специальной меткой. 762 | 2. Во время второго этапа происходит повторный проход по дереву объектов, в ходе которого непомеченные в первом этапе объекты перерабатываются 763 | 3. Все метки стираются 764 | 765 | [Подробнее](https://habr.com/ru/company/rshb/blog/668600/) 766 | 767 | --- 768 | 769 | ### Task Runners 770 | ![image](https://user-images.githubusercontent.com/80569772/211004726-1eeef86f-cebf-41de-8bb3-a8485257565f.png) 771 | - `Platform Task Runner`: Основной поток платформы. Здесь выполняется код плагинов. Для получения дополнительной информации см. документацию по UIKit для iOS или документацию по MainThread для Android. Этот поток не отображается в наложении производительности. 772 | - `UI Task Runner`: Поток UI выполняет код Dart в виртуальной машине Dart VM. Этот поток включает в себя код, написанный вами, и код, выполняемый фреймворком Flutter от имени вашего приложения. Когда ваше приложение создает и отображает сцену, поток UI создает дерево слоев - легкий объект, содержащий команды рисования, не зависящие от устройства, и отправляет дерево слоев в растровый поток для отображения на устройстве. Не блокируйте этот поток! Показан в нижней строке оверлея производительности. 773 | - `Raster Task Runner`: Растровый поток получает дерево слоев и отображает его, обращаясь к GPU (графическому процессору). Вы не можете напрямую обращаться к растровому потоку или его данным, но если этот поток работает медленно, то это результат того, что вы сделали в коде Dart. В этом потоке работают графические библиотеки Skia и Impeller. Они показаны в верхней строке оверлея производительности. Ранее этот поток был известен как "GPU-поток", поскольку он выполняет растеризацию для GPU. Однако он выполняется на центральном процессоре. Мы переименовали его в "растровый поток", поскольку многие разработчики ошибочно (но вполне обоснованно) полагали, что этот поток работает на GPU. 774 | - `IO Task Runner`: Выполняет дорогостоящие задачи (в основном ввод-вывод), которые в противном случае блокировали бы работу потоков пользовательского интерфейса или растровых потоков. Этот поток не отображается в оверлее производительности. 775 | 776 | [Подробнее](https://www.programmersought.com/article/81813680395/), [Подробнее 2](https://medium.com/flutter-community/the-layer-cake-widgets-elements-renderobjects-7644c3142401) 777 | 778 | 779 | ## Архитектура 780 | 781 | ### Архитектура 782 | Архитектура - это набор решений по организации программы. Таких, как деление программы на слои, построение связей между ними, управление состоянием, связь с UI. Хорошая архитектура делает слои в приложении слабо связанными, что упрощает внесение изменений, повышает тестируемость кода, упрощает систему 783 | 784 | --- 785 | 786 | ### Чистая архитектура 787 | Чистая архитектура - архитектура, которая следует `SOLID` и делится на три независимых слоя: 788 | - `Data (datasources, models, repositories)` получение данных извне 789 | - `Domain (entities, repositories interfaces, usecases)` бизнес правила 790 | - `Presentation (bloc, pages, widgets)` отображение 791 | 792 | [Пример](https://github.com/ResoCoder/flutter-tdd-clean-architecture-course) 793 | 794 | --- 795 | 796 | ### Управление состоянием 797 | 798 | **Vanilla** 799 | 800 | `Плюсы` 801 | - Низкий порог вхождения. 802 | - Не требуются сторонние библиотеки. 803 | 804 | `Минусы` 805 | - При изменении состояния виджета дерево виджетов каждый раз целиком пересоздается. 806 | - Нарушает принцип единственной ответственности. Виджет отвечает не только за создание UI, но и за загрузку данных, бизнес-логику и управление состоянием. 807 | - Решения о том как именно отображать текущее состояние принимаются прямо в UI коде. Если состояние станет более сложным, то читаемость кода сильно понизится. 808 | 809 | `Использование:` 810 | - Widget State 811 | 812 | **BLoC** 813 | 814 | `Плюсы` 815 | - Четкое разделение ответственности 816 | - Предсказуемые преобразования Event to State 817 | - Реактивность. Нет необходимости в вызове дополнительных методов 818 | 819 | `Минусы` 820 | - Обязательность состояния в Bloc-е 821 | - Частые изменения библиотеки 822 | - Зависимость от сторонней библиотеки 823 | 824 | `Использование:` 825 | - Widget State 826 | - App State 827 | 828 | **Redux** 829 | 830 | `Плюсы` 831 | - Единое состояние 832 | - Все экшены доступны всем 833 | 834 | `Минусы` 835 | - Единое состояние 836 | - Зависимость от сторонней библиотеки 837 | - Большое количество boilerplate кода 838 | - Все экшены доступны всем 839 | 840 | `Использование:` 841 | - Widget State 842 | - App State 843 | 844 | **Provider** 845 | 846 | `Плюсы` 847 | - Скоупы на поддеревья 848 | - Flutter ориентирован 849 | - Нет статики 850 | - Готовые провайдеры 851 | 852 | `Минусы` 853 | - Завязка на фреймворк 854 | - Только 1 провайдер одного типа 855 | - Зависимость от сторонней библиотеки 856 | 857 | `Использование:` 858 | - App State 859 | - Частично DI 860 | 861 | **Riverpod** 862 | 863 | `Плюсы:` 864 | - Скоупы на поддеревья 865 | - Flutter ориентирован 866 | - Нет статики 867 | - Готовые провайдеры 868 | 869 | `Минусы:` 870 | - Зависимость от сторонней библиотеки 871 | - Циклические зависимости падают в runtime-е 872 | 873 | `Использование:` 874 | - Widget State 875 | - App State 876 | - DI 877 | 878 | --- 879 | 880 | ### Dependency Injection 881 | `Dependency injection (DI)` - это механизм, который позволяет сделать взаимодействующие в приложении объекты слабосвязанными с помощью интерфейсов. Это делает всю систему более гибкой, более адаптируемой и расширяемой 882 | 883 | --- 884 | 885 | ### Архитектурные патерны 886 | ![](https://fuzeservers.ru/wp-content/uploads/2/6/8/268a107e69309f0529c18aae72769bdb.png) 887 | **MVVM** 888 | 889 | `Части:` 890 | - `Model` содержит в себе всю логику приложения, она хранит и обрабатывает данные, при этом не взаимодействуя с пользователем напрямую 891 | - `View` отображает данные, которые ему передали 892 | - `ViewModel` связывает модель и представление (передаёт данные между ними) 893 | 894 | `Использование:` 895 | - Используется в ситуации, когда возможно связывание данных без необходимости ввода специальных интерфейсов представления (т.е. отсутствует необходимость реализовывать IView); 896 | - Частым примером является технология WPF. 897 | 898 | [Подробнее](https://habr.com/ru/post/427327/) [Пример](https://github.com/jitsm555/Flutter-MVVM) 899 | 900 | **MVC** 901 | 902 | `Части:` 903 | - `Model` содержит в себе всю логику приложения, она хранит и обрабатывает данные, при этом не взаимодействуя с пользователем напрямую 904 | - `View` отображает данные, которые ему передали 905 | - `Controller` перехватывает событие извне и в соответствии с заложенной в него логикой, реагирует на это событие изменяя Mодель, посредством вызова соответствующего метода. После изменения Модель использует событие о том что она изменилась, и все подписанные на это события Представления, получив его, обращаются к Модели за обновленными данными, после чего их и отображают 906 | 907 | `Использование:` 908 | - Используется в ситуации, когда невозможно связывание данных (нельзя использовать Binding); 909 | 910 | [Пример](https://github.com/flutter-devs/Flutter_MVC) 911 | 912 | **MVP** 913 | 914 | `Части:` 915 | - `Model` содержит в себе всю логику приложения, она хранит и обрабатывает данные, при этом не взаимодействуя с пользователем напрямую 916 | - `View` отображает данные, которые ему передали 917 | - `Presenter` подписывается на события представления, по запросу изменяет модель, обновляет представление 918 | 919 | `Использование:` 920 | - Используется в ситуации, когда связь между представление и другими частями приложения невозможна (и Вы не можете использовать MVVM или MVP); 921 | 922 | --- 923 | 924 | ### Способы осуществления навигации 925 | **Navigator** 926 | - Идёт из коробки 927 | 928 | **Go Router** 929 | - Парсинг пути и параметров запроса (например, "user/:id") 930 | - Поддержка deep-links 931 | - Поддержка перенаправления - вы можете перенаправить пользователя на другой URL-адрес в зависимости от состояния приложения 932 | - Именованные роуты 933 | 934 | **Auto Route** 935 | - Парсинг пути и параметров запроса (например, "user/:id") 936 | - Поддержка deep-links 937 | - Защищённые маршруты 938 | - Именованные роуты 939 | - Разные варианты анимаций 940 | 941 | --- 942 | 943 | ### Базы данных 944 | **Нереляционные (NoSQL):** 945 | **Hive** 946 | 947 | `Плюсы:` 948 | - Реализация на чистом Dart, без платформенного кода, за счёт чего одинаково работает на разных платформах 949 | - Прост в использовании 950 | - Быстрая запись / чтение 951 | - Мало boilerplate кода 952 | - Наличие кодогенерации 953 | - Поддерживается на всех платформах 954 | 955 | `Минусы:` 956 | - Связи между объектами нужно поддерживать вручную 957 | - Ограничение по количеству адаптеров для объектов - 224 958 | - Ограничение по количеству полей в адаптере - 255 959 | - Плохо подходит для работы с большим объемом данных 960 | - Выгружает всю бд в память 961 | - Нельзя получить доступ к box-у, созданному в другом изоляте 962 | - Наличие кодогенерации 963 | - Нет миграций 964 | 965 | `Использование:` 966 | - Небольшой объём данных 967 | - Необходимость в сохранении своих дата моделей 968 | 969 | **Shared Preferences** 970 | 971 | `Плюсы:` 972 | - Прост в использовании 973 | - Синхронное чтение из кэша в памяти 974 | - Поддерживается на всех платформах 975 | 976 | `Минусы:` 977 | - Разные реализации для Android/iOS и других платформ 978 | - Обращение к платформенному коду 979 | - Не гарантируется запись на диск после успешного выполнения метода 980 | - Нельзя сохранять сложные объекты из коробки 981 | 982 | `Использование:` 983 | - Небольшой объём данных 984 | - Необходимость в быстром внедрении решения 985 | - Сохранение настроек приложения в виде примитивных данных 986 | 987 | **Реляционные (SQL):** 988 | **SQFLite** 989 | 990 | `Плюсы` 991 | - Есть миграции 992 | - Поддерживает связи между сущностями 993 | - Не выгружает бд в оперативную память 994 | - Возможность написания сложных запросов на SQL 995 | 996 | `Минусы:` 997 | - Сложен в использовании 998 | - Не поддерживается в Web, Linux, Windows 999 | - Скорость работы ниже чем у NoSQL 1000 | - На разных OS и версиях могут быть разные версии SQLite 1001 | 1002 | `Использование:` 1003 | - Большой объём данных 1004 | - Хранение сложно структурированных данных 1005 | 1006 | **Drift** 1007 | - Есть миграции 1008 | - Поддерживает связи между сущностями 1009 | - Не выгружает бд в оперативную память 1010 | - Возможность написания сложных запросов на SQL 1011 | 1012 | `Плюсы` 1013 | - Есть миграции 1014 | - Быстрый 1015 | - Поддерживается на всех платформах 1016 | 1017 | `Минусы:` 1018 | - Сложен в использовании 1019 | - Скорость работы ниже чем у NoSQL 1020 | 1021 | `Использование:` 1022 | - Большой объём данных 1023 | - Хранение сложно структурированных данных 1024 | 1025 | 1026 | ## Тестирование 1027 | 1028 | 1029 | ### Виды тестов 1030 | - `Модульный тест` тестирует одну функцию, метод или класс. Его цель - проверить правильность работы определенной функции, метода или класса. Внешние зависимости для тестируемого модуля обычно передаются как параметр. 1031 | - `Виджет тест` тестирует один виджет. Цель такого теста — убедиться, что пользовательский интерфейс виджета выглядит и взаимодействует, как запланировано. Тестирование виджета происходит в тестовой среде, которая обеспечивает контекст жизненного цикла виджета. Также тестируемый виджет должен иметь возможность получать действия и события пользователя и отвечать на них . 1032 | - `Интеграционный тест` тестирует все приложение или его большую часть. Цель интеграционного теста — убедиться, что все тестируемые виджеты и сервисы работают вместе, как ожидалось. Кроме того, вы можете использовать интеграционные тесты для проверки производительности вашего приложения. Как правило, интеграционный тест выполняется на реальном устройстве или эмуляторе. 1033 | 1034 | --- 1035 | 1036 | ### TDD 1037 | `TDD` — это методика разработки приложений, при которой сначала пишется тест, покрывающий желаемое изменение, а затем — код, который позволит пройти тест. 1038 | 1039 | 1040 | ## Паттерны разработки 1041 | *Порождающие*. Отвечают за удобное и безопасное создание новых объектов или даже целых семейств объектов. 1042 | - Factory Method (Фабричный Метод). Порождающий паттерн проектирования, который определяет общий интерфейс для создания объектов в суперклассе, позволяя подклассам изменять тип создаваемых объектов. 1043 | - Abstract Factory (Абстрактная Фабрика). Порождающий паттерн проектирования, который позволяет создавать семейства связанных объектов, не привязываясь к конкретным классам создаваемых объектов. 1044 | - Builder (Строитель). Порождающий паттерн проектирования, который позволяет создавать сложные объекты пошагово. Строитель даёт возможность использовать один и тот же код строительства для получения разных представлений объектов. 1045 | - Prototype (Прототип). Порождающий паттерн проектирования, который позволяет копировать объекты, не вдаваясь в подробности их реализации. 1046 | - Singleton (Одиночка). Порождающий паттерн проектирования, который гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа. 1047 | 1048 | *Структурные*. Отвечают за построение удобных в поддержке иерархий классов. 1049 | - Adapter (Адаптер). Структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. 1050 | - Bridge (Мост). Структурный паттерн проектирования, который разделяет один или несколько классов на две отдельные иерархии — абстракцию и реализацию, позволяя изменять их независимо друг от друга. 1051 | - Composite (Компоновщик). Структурный паттерн проектирования, который позволяет сгруппировать множество объектов в древовидную структуру, а затем работать с ней так, как будто это единичный объект. 1052 | - Decorator (Декоратор). Структурный паттерн проектирования, который позволяет динамически добавлять объектам новую функциональность, оборачивая их в полезные «обёртки». 1053 | - Facade (Фасад). Структурный паттерн проектирования, который предоставляет простой интерфейс к сложной системе классов, библиотеке или фреймворку. 1054 | - Flyweight (Легковес). Паттерн проектирования, который позволяет вместить бóльшее количество объектов в отведённую оперативную память. Легковес экономит память, разделяя общее состояние объектов между собой, вместо хранения одинаковых данных в каждом объекте. 1055 | - Proxy (Заместитель). Структурный паттерн проектирования, который позволяет подставлять вместо реальных объектов специальные объекты-заменители. Эти объекты перехватывают вызовы к оригинальному объекту, позволяя сделать что-то до или после передачи вызова оригиналу. 1056 | 1057 | *Поведенческие*. Решают задачи эффективного и безопасного взаимодействия между объектами программы. 1058 | - Chain of Responsibility (Цепочка Обязанностей). Поведенческий паттерн проектирования, который позволяет передавать запросы последовательно по цепочке обработчиков. Каждый последующий обработчик решает, может ли он обработать запрос сам и стоит ли передавать запрос дальше по цепи. 1059 | - Command (Команда). Поведенческий паттерн проектирования, который превращает запросы в объекты, позволяя передавать их как аргументы при вызове методов, ставить запросы в очередь, логировать их, а также поддерживать отмену операций. 1060 | - Iterator (Итератор). Поведенческий паттерн проектирования, который даёт возможность последовательно обходить элементы составных объектов, не раскрывая их внутреннего представления. 1061 | - Mediator (Посредник). Поведенческий паттерн проектирования, который позволяет уменьшить связанность множества классов между собой, благодаря перемещению этих связей в один класс-посредник. 1062 | - Memento (Снимок). Поведенческий паттерн проектирования, который позволяет сохранять и восстанавливать прошлые состояния объектов, не раскрывая подробностей их реализации. 1063 | - Observer (Наблюдатель). Поведенческий паттерн проектирования, который создаёт механизм подписки, позволяющий одним объектам следить и реагировать на события, происходящие в других объектах. 1064 | - State (Состояние). Поведенческий паттерн проектирования, который позволяет объектам менять поведение в зависимости от своего состояния. Извне создаётся впечатление, что изменился класс объекта. 1065 | - Strategy (Стратегия). Поведенческий паттерн проектирования, который определяет семейство схожих алгоритмов и помещает каждый из них в собственный класс, после чего алгоритмы можно взаимозаменять прямо во время исполнения программы. 1066 | - Template Method (Шаблонный Метод). Поведенческий паттерн проектирования, который определяет скелет алгоритма, перекладывая ответственность за некоторые его шаги на подклассы. Паттерн позволяет подклассам переопределять шаги алгоритма, не меняя его общей структуры. 1067 | - Visitor (Посетитель). Поведенческий паттерн проектирования, который позволяет добавлять в программу новые операции, не изменяя классы объектов, над которыми эти операции могут выполняться. 1068 | 1069 | [Подробнее](https://refactoring.guru/ru/design-patterns/catalog) 1070 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | ![Flutter Interview](https://github.com/p0dyakov/flutter_interview/assets/80569772/68dccc7f-b4f2-4eca-932a-8f9fe5559b5f) 2 | **Repositories:** [Flutter Interview](https://github.com/p0dyakov/flutter_interview), [Flutter Roadmap](https://github.com/p0dyakov/flutter_roadmap), [Flutter Acrticles](https://github.com/p0dyakov/flutter_articles), [Flutter Best Packages](https://github.com/p0dyakov/flutter_best_packages), [Flutter Tools](https://github.com/p0dyakov/flutter_tools) 3 | 4 | 5 | 6 | 7 | - [General](#general) 8 | * [OOP](#oop) 9 | * [SOLID](#solid) 10 | * [Git Flow](#git-flow) 11 | * [Data structures](#data-structures) 12 | * [Imperative and declarative programming](#imperative-and-declarative-programming) 13 | * [Stack and heap](#stack-and-heap) 14 | * [DAO, DTO, VO, BO](#dao-dto-vo-bo) 15 | * [DI and Service Locator](#di-and-service-locator) 16 | - [Dart](#dart) 17 | * [final and const](#final-and-const) 18 | * [JIT and AOT](#jit-and-aot) 19 | * [Hot Restart and Hot Reload](#hot-restart-and-hot-reload) 20 | * [HashCode](#hashcode) 21 | * [Extension](#extension) 22 | * [Mixin](#mixin) 23 | * [Sound Null Safety](#sound-null-safety) 24 | * [Type system](#type-system) 25 | * [Late](#late) 26 | * [Generics](#generics) 27 | * [Dart VM](#dart-vm) 28 | * [Zones](#zones) 29 | * [Types of errors](#types-of-errors) 30 | * [Naming rules](#naming-rules) 31 | * [Never](#never) 32 | * [Covariant](#covariant) 33 | * [Annotations](#annotations) 34 | * [int8, uint8, int16, uint16...](#int8-uint8-int16-uint16) 35 | * [Future](#future) 36 | * [Future Constructors](#future-constructors) 37 | * [Await under the hood](#await-under-the-hood) 38 | * [Event Loop](#event-loop) 39 | * [Completer](#completer) 40 | * [Stream](#stream) 41 | * [Generators (sync* / async*) ](#generators-sync-async) 42 | * [Multithreading in Dart and Flutter ](#multithreading-in-dart-and-flutter) 43 | * [Isolate](#isolate) 44 | * [Compute](#compute) 45 | * [Multithreading issues](#multithreading-issues) 46 | - [Flutter](#flutter) 47 | * [Stateless and Stateful widgets](#stateless-and-stateful-widgets) 48 | * [Stateful Widget Lifecycle](#stateful-widget-lifecycle) 49 | * [BuildContext](#buildcontext) 50 | * [InheritedWidget](#inheritedwidget) 51 | * [Trees](#trees) 52 | * [Widget](#widget) 53 | * [Element](#element) 54 | * [RenderObject](#renderobject) 55 | * [Types of widgets](#types-of-widgets) 56 | * [Types of elements](#types-of-elements) 57 | * [The life cycle of an Element](#the-life-cycle-of-an-element) 58 | * [GlobalKeys](#globalkeys) 59 | * [LocalKeys](#localkeys) 60 | * [The Flutter device is under the hood](#the-flutter-device-is-under-the-hood) 61 | * [Execution model in Flutter](#execution-model-in-flutter) 62 | * [CustomPaint](#custompaint) 63 | * [WidgetsFlutterBinding](#widgetsflutterbinding) 64 | * [Bindings](#bindings) 65 | * [Platform Channels](#platform-channels) 66 | * [Build Modes](#build-modes) 67 | * [Package and Plugin](#package-and-plugin) 68 | * [FFI Plugin](#ffi-plugin) 69 | * [Animation stages](#animation-stages) 70 | * [Types of animations](#types-of-animations) 71 | * [What is a Tween](#what-is-a-tween) 72 | * [Tween animations](#tween-animations) 73 | * [Frame construction](#frame-construction) 74 | * [Layout calculation](#layout-calculation) 75 | * [BuildOwner](#buildowner) 76 | * [PipelineOwner](#pipelineowner) 77 | * [Garbage Collector](#garbage-collector) 78 | * [Task Runners](#task-runners) 79 | - [Architecture](#architecture) 80 | * [Architecture](#architecture-1) 81 | * [Clean architecture](#clean-architecture) 82 | * [State Management](#state-management) 83 | * [Dependency Injection ](#dependency-injection) 84 | * [Architectural patterns](#architectural-patterns) 85 | * [Ways to navigate](#ways-to-navigate) 86 | * [Databases](#databases) 87 | - [Testing](#testing) 88 | * [Types of tests](#types-of-tests) 89 | * [TDD](#tdd) 90 | - [Development patterns](#development-patterns) 91 | 92 | 93 | 94 | 95 | ## General 96 | 97 | 98 | ### OOP 99 | `Object-oriented programming` — this is a programming paradigm based on the representation of a program as a collection of objects, each of which is an instance of a certain class, and classes form an inheritance hierarchy. 100 | - `Abstraction` 101 | Modeling the interactions of entities in the form of abstract classes and interfaces to represent the system 102 | - `Encapsulation` 103 | Combining data and methods working with it in a class 104 | - `Inheritance` 105 | Creating new classes based on existing ones 106 | - `Polymorphism` 107 | Using objects with the same interface without information about the type and internal structure of the object 108 | 109 | --- 110 | 111 | ### SOLID 112 | - `Single Responsibility Principle` 113 | The class should only be responsible for one thing. 114 | - `Open-Closed Principle` 115 | Software entities should be open for expansion, but closed for modification. 116 | - `Liskov Substitution Principle (Barbara Liskov Substitution Principle)` 117 | The inheriting class should complement, not replace, the behavior of the base class. 118 | - `Interface Segregation Principle` 119 | Clients should not implement logic that they do not use. 120 | - `Dependency Inversion Principle` 121 | The modules of the upper levels should not depend on the modules of the lower levels. Classes of both upper and lower levels should depend on the same abstractions (and abstractions should not know about the details). 122 | 123 | --- 124 | 125 | ### Git Flow 126 | Feature 127 | 1. `The beginning of a new feature`. Creating a new branch `feature/future_name` from `develop` 128 | 2. `Completion of the feature`. Merge `feature/future_name` into `develop`, delete `feature/future_name` 129 | 3. `The beginning of the release`. Creating a release branch `release/vX.X.X`, responding from the `develop` branch 130 | 4. `Release Completion`. The release branch `release/vX.X.X` merges into `master`, the release is tagged, the release branch merges into `develop`, the release branch is deleted 131 | 132 | Fix 133 | 1. `The beginning of correction`. From the `master` branch, create a `hotfix/fix_name` 134 | 2. `Completion of correction`. From the `hotfix/fix_name` branch, the fix is merged into `develop` and `master`, the fix branch is deleted 135 | 136 | --- 137 | 138 | ### Data structures 139 | Data structures are needed to store data in a suitable way 140 | - `Arrays` 141 | - `Stacks` (*LIFO* - last in, first out) 142 | - `Queues` (*FIFO* - first in, first out) 143 | - `Linked lists` 144 | - `Trees` 145 | - `Graphs` 146 | - `Hash tables` 147 | 148 | --- 149 | 150 | ### Imperative and declarative programming 151 | - `Imperative style` - we describe **how** to achieve the desired result 152 | - `Declarative style` - we describe ** what kind of result ** we need 153 | 154 | --- 155 | 156 | ### Stack and heap 157 | - A `stack` is an area of RAM that stores temporary data such as local variables and function return addresses. The amount of memory allocated for the stack is limited. The stack works in LIFO order 158 | - A `heap` is an area of RAM in which data created during program execution is stored. The heap is used to dynamically allocate memory for objects that can change size during program execution. The heap size is set when the application is launched, but, unlike the stack, it is limited only physically. Memory allocation on the heap is slower than on the stack. 159 | 160 | --- 161 | 162 | ### DAO, DTO, VO, BO 163 | - `DAO (Data Access Object, data access Object)` is an abstract interface to some type of database or other storage mechanism 164 | - `DTO (Data Transfer Object, data transfer object)` is an object for transferring data (objects without behavior) between layers 165 | - `VO (Value Object, value object)` ⎼ is an object without special methods, having a set of properties (fields) of primitive data types, or also a Value object 166 | - `BO (Business Object, business object)` is an object that represents an entity from a certain "domain", that is, the industry for which the application was developed 167 | 168 | --- 169 | 170 | ### DI and Service Locator 171 | - `DI` - passing class dependencies through constructor parameters 172 | - `Service Locator` - singleton / class with a set of static methods 173 | 174 | The `Service Locator` can be accessed from anywhere in the code. This is its main disadvantage 175 | 176 | 177 | ## Dart 178 | 179 | ### final and const 180 | - `final` is calculated in runtime. Only the instance value is constant. When using a final instance, a new memory area is allocated in memory, even if the object value is identical. 181 | - `const` is calculated at compile time. Not only the value is constant, but also the instance itself. When using a const variable, a new memory area is not allocated, but a reference to an existing instance is used. 182 | 183 | --- 184 | 185 | ### JIT and AOT 186 | - `Just-in-time (JIT) compilation` is a type of compilation that is performed directly while the program is running, which significantly speeds up the development cycle. But it should be borne in mind that the program may slow down and run slower 187 | - `Ahead-of-time (AOT) compilation` is a type of compilation that is fully executed before running a program. The Dart code is converted to native machine code, which is then packaged into a binary file with the extension `.so` for `Android` or `.dylib` for `iOS`. `AOT` Takes longer than `JIT`, but as a result, the program runs much faster. 188 | 189 | --- 190 | 191 | ### Hot Restart and Hot Reload 192 | - `Hot Reload` loads the changes to the `Dart VM` and reboots the widget tree, saving the state. Does not restart `main()` and `initState()` 193 | - `Hot Restart` loads the changes to the `Dart VM` and restarts the entire application. Restarts `main()` and `initState()`. The state is not saved 194 | 195 | --- 196 | 197 | ### HashCode 198 | A `hash code` is a getter for any object that returns an `int`. It is needed when saving an object to `map` or `set`. Hash codes must be the same for objects that are equal to each other according to the == operator 199 | `int get hashCode => Object.hash(runtimeType, ..., ...);` 200 | 201 | --- 202 | 203 | ### Extension 204 | `Extension` is a syntactic sugar that allows you to extend an existing class (add methods, operators, setters and getters) 205 | 206 | --- 207 | 208 | ### Mixin 209 | A `mixin` is a multiple inheritance mechanism that allows classes to use the functionality of other classes without explicit inheritance. 210 | 211 | Mixins in Dart are defined by the keyword `mixin`. They can contain methods, fields, and getters/setters, but they cannot have constructors. Instead, mixins are initialized automatically when they are applied to a class. The `with` operator is used to use mixins 212 | 213 | If the mixins have a method with the same name, then the implementation that is specified in the last mixin will remain. Since mixins will override this method 214 | 215 | --- 216 | 217 | ### Sound Null Safety 218 | `Sound Null Safety` is an addition to the Dart language that strengthens the type system by separating types that allow the value of `Null` from types that do not allow the value of `Null`. This allows developers to prevent errors related to `Null`. 219 | 220 | --- 221 | 222 | ### Type system 223 |

224 | 225 |

226 | With the advent of null safety in Dart, the hierarchy of classes and interfaces has been changed to accommodate new type safety requirements. Here are the main changes: 227 | 228 | 1. **Adding non-nullable types**: 229 | - Non-nullable types indicate that the value cannot be null. 230 | - All existing types have been divided into non-nullable and nullable versions. For example, `int` became `int` (non-nullable) and `int?` (nullable) 231 | 232 | 2. **The new root of the hierarchy is "Object?"**: 233 | - Has a new root class `Object` been introduced?`, which can be null. In previous versions of Dart, the root class was `Object` 234 | 235 | 3. **Changes in the error hierarchy**: 236 | - A new class `NullThrownError` has been introduced, which represents an error that occurs when trying to throw a `null` exception 237 | 238 | 4. **`late` and `required`**: 239 | - The keywords `late` and `required` have been introduced to indicate variables that can be initialized later and must be initialized when declaring, respectively. 240 | 241 | --- 242 | 243 | ### Late 244 | `Late` is a keyword in dart that allows you to declare a non-nullable variable without setting a value for it. The value is initialized only when we access it. 245 | 246 | --- 247 | 248 | ### Generics 249 | `Generics` are parameterized types. They allow the program to get away from being tightly bound to certain types, define the functionality so that it can use data of any type and ensure their security. Generalizations also reduce code repeatability and give you the opportunity to provide a single interface and implementation for many types. 250 | 251 | --- 252 | 253 | ### Dart VM 254 | `Dart VM (Dart virtual machine)` - Dart runtime environment 255 | 256 | Components: 257 | - `Execution Environment` 258 | - `Garbage Collector` 259 | - `Basic libraries and native methods` 260 | - `System debugging` 261 | - `Profiler` 262 | - `ARM Architecture Simulator` 263 | 264 | --- 265 | 266 | ### Zones 267 | A zone is a mechanism that allows you to manage and handle errors and other events that occur in certain areas of the code. 268 | 269 | 1. Protecting your application from termination due to an unhandled exception 270 | 2. Association of data known as `zone-local values` with individual zones 271 | 3. Redefining a limited set of methods, such as print() and scheduleMicrotask(), inside part or all of the code 272 | 4. Perform the operation every time the code enters or exits the zone. These operations may include starting or stopping a timer or saving a stacktrace. 273 | 274 | --- 275 | 276 | ### Types of errors 277 | `Exception` is a general class for exceptions that usually occur due to errors in the program, and they can be handled and recovered from: 278 | - DeferredLoadException 279 | - FormatException 280 | - IntegerDivisionByZeroException (marked as deprecated) 281 | - IOException 282 | - FileSystemException 283 | - PathNotFoundException 284 | - HttpException 285 | - RedirectException 286 | - ProcessException 287 | - SignalException 288 | - SocketException 289 | - StdinException 290 | - StdoutException 291 | - TlsException 292 | - CertificateException 293 | - HandshakeException 294 | - WebSocketException 295 | - IsolateSpawnException 296 | - TimeoutException 297 | - NullRejectionException 298 | 299 | `Error` is a class for errors that usually cannot be repaired, and they indicate serious problems in the program or system: 300 | - OSError 301 | - ArgumentError 302 | - IndexError 303 | - RangeError 304 | - AssertionError 305 | - AsyncError 306 | - ConcurrentModificationError 307 | - JsonUnsupportedObjectError 308 | - JsonCyclicError 309 | - NoSuchMethodError 310 | - OutOfMemoryError 311 | - RemoteError 312 | - StackOverflowError 313 | - StateError 314 | - TypeError 315 | - UnimplementedError 316 | - UnsupportedError 317 | 318 | --- 319 | 320 | ### Naming rules 321 | - Variables and constants - `lowerCamelCase` 322 | - Classes, mixins, enums - `UpperCamelCase` 323 | - Files - `snake_case` 324 | 325 | --- 326 | 327 | ### Never 328 | `Never` is a type, meaning that no type is allowed and `Never` itself cannot be created. It is used as a return type in case of a guaranteed error. 329 | 330 | --- 331 | 332 | ### Covariant 333 | `Covariant` is a keyword in dart that indicates that the type of the return value can be changed to a narrower type in the subclass. 334 | 335 | --- 336 | 337 | ### Annotations 338 | `Annotations` are syntactic metadata that can be added to the code. In other words, it is an opportunity to add additional information to any component of the code, for example, to a class or method. Annotations always start with the character `@` (`@override`, `@required`). Any class can serve as an annotation if a const constructor is defined in it. 339 | 340 | --- 341 | 342 | ### int8, uint8, int16, uint16... 343 | |Specifier|Common Equivalent|Bytes|Minimum value|Maximum value| 344 | |--|--|--|--|--| 345 | |int8|signed char|1|-128|127| 346 | |uint8|unsigned char|1|0|255| 347 | |int16|short|2|-32,768|32,767| 348 | |uint16|unsigned short|2|0|65,535| 349 | |int32|long|4|-2,147,483,648|2,147,483,647| 350 | |uint32|unsigned long|4|0|4,294,967,295| 351 | |int64|long long|8|-9,223,372,036,854,775,808|9,223,372,036,854,775,807| 352 | |uint64|unsigned long long|8|0|18,446,744,073,709,551,615| 353 | 354 | --- 355 | 356 | ### Future 357 | `Future` is a wrapper over the result of an asynchronous operation. The Future code is NOT executed in parallel, but is executed in a sequence defined by the Event Loop. 358 | Future states: 359 | - Incomplete - the operation is not completed 360 | - Completed with Result - the operation was completed successfully 361 | - Completed with Error - the operation was completed with an error 362 | 363 | --- 364 | 365 | ### Future Constructors 366 | - `Future(FutureOr computation())`: Creates a future object that uses the Timer.run method to run the computation function asynchronously and returns its result. 367 | - `FutureOr`: specifies that the calculation function should return either a Future object or an object of type T. For example, to get a Future object, the calculation function should return either a Future object or an int object 368 | - `Future.delayed(Duration duration, [FutureOr computation()])`: creates a Future object that runs after the time delay specified through the first Duration parameter. The second optional parameter indicates the function that runs after this delay. 369 | - `Future.error(Object error, [StackTrace stackTrace])`: Creates a Future object that contains information about the error that occurred. 370 | - `Future.microtask(FutureOr computation())`: Creates a Future object that uses the scheduleMicrotask function to run the computation function asynchronously and return its result. 371 | - `Future.sync(FutureOr computation())`: Creates a Future object that contains the result of an immediately called computation function. 372 | - `Future.value([FutureOr value])`: creates a Future object that contains the value value. 373 | 374 | --- 375 | 376 | ### Await under the hood 377 | Under the hood, `await` moves all subsequent code to `then` at `Future`, which we are waiting for 378 | 379 | --- 380 | 381 | ### Event Loop 382 | The `Event Loop` is an eternal loop that executes all incoming tasks to the isolate. 383 | It has two FIFO task queues: 384 | 385 | `MicroTask Queue` 386 | It is used for very short actions that must be performed asynchronously, immediately after completing any instruction before passing control back to the Event Loop. The MicroTask queue takes precedence over the Event queue 387 | 388 | `Event Queue` 389 | It is used for scheduling operations that receive results from external events (I/O operations, gestures, drawing, timers, threads) 390 | 391 | --- 392 | 393 | ### Completer 394 | The `Completer` allows you to supply a Future, send an execution event, or an error event. This can be useful when you need to make a Future chain and return the result. 395 | 396 | --- 397 | 398 | ### Stream 399 | A `stream` is a sequence of asynchronous events. Stream tells you that there is an event and when it will be ready 400 | - `Single subscription` is a type of stream where there can be only one subscriber. 401 | - `Broadcast` is a type of stream where there can be many subscribers. At the same time, Broadcast streams give their data regardless of whether someone is subscribed to them or not. Stream subscribers receive events only from the moment of subscription, and not from the moment of the start of the stream`s life 402 | 403 | --- 404 | 405 | ### Generators (sync* / async*) 406 | `Generator` this is a keyword that allows you to create a sequence of values using `yield` 407 | - *sync** is a synchronous generator. Returns `Iterable` 408 | - *async** is an asynchronous generator. Returns `Stream` 409 | 410 | --- 411 | 412 | ### Multithreading in Dart and Flutter 413 | `Dart` is a single—threaded programming language. It executes one instruction at a time. But at the same time, we can run the code in a separate thread using `Isolate` 414 | 415 | --- 416 | 417 | ### Isolate 418 | `Isolate` is a lightweight process (execution thread) that runs in parallel with other threads and processes in the application. Each `Isolate` in Dart has its own instance of the Dart virtual machine, its own memory and is controlled using its own `Event Loop`. 419 | 420 | --- 421 | 422 | ### Compute 423 | `Compute` is a function that creates an isolate and runs the passed code. 424 | 425 | --- 426 | 427 | ### Multithreading issues 428 | 429 | - `Deadlock` — each of the threads is waiting for events that other threads can provide 430 | - `Race conditions` — a manifestation of the nondeterminism of the program executor with different relative order of execution of commands in different threads 431 | - `Lock Contention` — the main time of the stream is spent not performing useful work, but waiting for a resource blocked by another stream 432 | - `Live Lock` — the thread captures the resource, but after it is convinced that it cannot complete the work, it releases the resource, canceling the results 433 | 434 | 435 | ## Flutter 436 | 437 | 438 | ### Stateless and Stateful widgets 439 | - `StatelessWidget` is a widget that has no state and does not change its properties during the operation of the application. They can only be changed through external events that occur in the parent widgets. 440 | - `StatefulWidget` is a widget that stores the state, during the operation of the application it can change it dynamically using `setState()`. 441 | 442 | --- 443 | 444 | ### Stateful Widget Lifecycle 445 | 1. `createState()` is called once and creates a changeable state for this widget at a specified location in the tree 446 | 2. `mounted is true` 447 | 3. `initState()` is called once during initialization 448 | 4. `didChangeDependencies()` is called once after initialization and further upon notifications from the Inherited widgets at the top of the tree on which the widget depends 449 | 5. `build()` is called every time you redraw 450 | 6. `didUpdateWidget(Widget oldWidget)` is called every time the widget configuration is updated 451 | 7. `setState()` is called imperatively for redrawing 452 | 8. `deactivate()` is called when a previously active element is moved to the list of inactive elements, while being removed from the tree 453 | 9. `dispose()` is called when this object is removed from the tree **forever** 454 | 10. `mounted is false` 455 | 456 | --- 457 | 458 | ### BuildContext 459 | The `BuildContext` is the interface that implements the `Element`. 460 | 461 | `BuildContext` can be useful when needed: 462 | - Get a reference to the `RenderObject` object corresponding to the widget (or, if the widget is not a Renderer, then a descendant widget) 463 | - Get the size of the `RenderObject` 464 | - Access the tree and get the nearest parent `InheritedWidget`. This is used by virtually all widgets that usually implement the of method (for example, `MediaQuery.of(context)`, `Theme.of(context)` etc.) 465 | 466 | --- 467 | 468 | ### InheritedWidget 469 | An `InheritedWidget` is a widget that provides its descendants with the ability to interact with the data stored in it. Solves the problem with passing data through constructors. It can notify widgets at the bottom of the tree about changes in its own data, thereby provoking their redrawing. 470 | To get an Inherited widget, call `context.dependOnInheritedWidgetOfExactType()`in `didChangeDependencies()` 471 | 472 | *The complexity of the operation of obtaining InheritedWidget - O(1). This speed is achieved due to the fact that Inherited widgets are stored as a hash table in the `Element`.* 473 | 474 | --- 475 | 476 | ### Trees 477 | ![](https://docs.flutter.dev/assets/images/docs/arch-overview/trees.png ) 478 | - The `Widget Tree` consists of `Widgets` that are used to describe the user interface 479 | - The `Element Tree` consists of `Elements` that manage the widget lifecycle and link widgets and rendering objects. 480 | - The `Render Tree` consists of `RenderObject`, which are used to determine the size, position, geometry, and areas of the screen that can be affected by gestures 481 | 482 | --- 483 | 484 | ### Widget 485 | A `Widget` is an immutable description of a part of the user interface. The widget is associated with the element that controls the rendering. Widgets form a structure, not a tree 486 | 487 | --- 488 | 489 | ### Element 490 | An `Element` is a mutable representation of a widget at a specific location in the tree. They manage the lifecycle, link widgets and rendering objects. 491 | 492 | --- 493 | 494 | ### RenderObject 495 | `RenderObject` is a mutable object of the visualization tree. It has a parent object, as well as a data field that the parent object uses to store specific information about the object itself, for example, its position. This object is responsible for rendering, accounting for sizes and constraints, listening and processing clicks. If necessary, it is marked as `dirty`. It is redrawn using its own `layer` method 496 | 497 | --- 498 | 499 | ### Types of widgets 500 | `Proxies` are widgets that store some information and make it available to posterity. These widgets are not directly involved in shaping the user interface, but are used to get the information they can provide. 501 | - `InheritedWidget` 502 | - `ParentDataWidget` (`LayoutId`, `Flexible`, `KeepAlive`, etc.) 503 | - `NotificationListener` 504 | 505 | `Renderer` are widgets that are directly related to the layout of the screen, as they determine the size, position, and rendering 506 | - `Row` 507 | - `Column` 508 | - `Stack` 509 | - `Padding` 510 | - `Align` 511 | - `Opacity` 512 | 513 | `Component` are widgets that do not directly provide final information related to dimensions, positions, appearance, but rather data (or hints) that will be used to obtain that final information. 514 | - `RaisedButton` 515 | - `Scaffold` 516 | - `Text` 517 | - `GestureDetector` 518 | - `Container` 519 | 520 | --- 521 | 522 | ### Types of elements 523 | ![image](https://user-images.githubusercontent.com/80569772/205450564-87d6c2d0-a994-4d1d-bbaa-2c8f7fb07385.png) 524 | A `ComponentElement` is a layout element that does not explicitly contain drawing/display logic. There is a `build()` method that returns the widget. It is formed only when creating widgets `StatelessWidget`, `StatefulWidget`, `InheritedWidget`. 525 | - `ProxyElement` 526 | - `StatelessElement` 527 | - `StatefulElement` 528 | 529 | `RenderObjectElement` is a display element that is explicitly involved in drawing components on the screen. Contains a `RenderObject` and inherits from the `Element` class. It is formed when creating widgets `Padding`, `Column`, `Row`, `Center`, etc. 530 | - `LeafRenderObjectElement` 531 | - `ListWheelElement` 532 | - `MultiChildRenderObjectElement` 533 | - `RootRenderObjectElement` 534 | - `SingleChildRenderObjectElement` 535 | - `SliverMultiBoxAdaptorElement` 536 | - `SlottedRenderObjectElement` 537 | 538 | --- 539 | 540 | ### The life cycle of an Element 541 | 1. The element is created by calling the `Widget.createElement` method and is configured by the widget instance from which the method was called. 542 | 2. Using the `mount` method, the created element is added to the specified position of the parent element. When calling this method, child widgets are also associated and objects of the rendering tree are mapped to the elements. 543 | 3. The widget becomes active and should appear on the screen. 544 | 4. If the widget associated with an element changes (for example, if the parent element has changed), there are several scenarios. If the new widget has the same `runtimeType` and `key`, then the element is associated with it. Otherwise, the current element is removed from the tree, and a new element is created and associated with the new widget. 545 | 5. If the parent element decides to delete a child element, or an intermediate one between them, this will delete the rendering object and move this element to the inactive list, which will deactivate the element. 546 | 6. When an item is considered inactive, it is not on the screen. An element can be inactive only until the end of the current frame, if it remains inactive during this time, it is dismantled, after that it is considered non-existent and will no longer be included in the tree. 547 | 7. When you re-include elements in the tree, for example, if an element or its ancestors have a global key, it will be removed from the list of inactive elements, the `activate` method will be called, and the render object associated with this element will again be embedded in the rendering tree. This means that the item should appear on the screen again. 548 | 549 | --- 550 | 551 | ### GlobalKeys 552 | `GlobalKeys` are keys that provide access to widgets. For stateful widgets, global keys also provide access to the state. Allow widgets to change parents anywhere in the application without losing state. They must be unique to the entire application. 553 | 554 | --- 555 | 556 | ### LocalKeys 557 | `LocalKeys` are the keys that are needed to identify widgets in a collection with the same values and must be unique among widgets with the same parent widget. They can be used for tests: 558 | - `ValueKey` is a key that uses a value of a certain type to identify itself. Overrides the comparison operator. If the value is the same, then the keys are the same 559 | - `uniqueKey` is a key that is equal only to itself 560 | - `ObjectKey` is the key that is used to bind the widget identifier to the identifier of the object used to create this widget 561 | 562 | --- 563 | 564 | ### The Flutter device is under the hood 565 | ![image](https://user-images.githubusercontent.com/80569772/203052487-937d5923-9571-4752-9762-f0d6637b675e.png) 566 | 567 | The `framework level` is everything we are working with at the time of writing the application, and all the service classes that allow us to interact with the engine level. Everything related to this level is written on Dart. The `Flutter Framework` interacts with the `Flutter Engine` through an abstraction layer called `Window` 568 | 569 | The `engine level` is a lower level than the framework level, it contains classes and libraries that allow the framework level to work. Including the `Dart virtual machine`, `Skia` and so on. 570 | 571 | `Platform level` — specific mechanisms related to a specific launch platform. 572 | 573 | The `Flutter Engine` notifies the `Flutter Framework` when: 574 | - The event of interest occurs at the device level (orientation change, settings change, memory problem, application operation status...) 575 | - Some kind of event occurs at the glass level (gesture) 576 | - The platform channel sends some data 577 | - But also mostly when the Flutter Engine is ready to render a new frame 578 | 579 | --- 580 | 581 | ### Execution model in Flutter 582 | 1. A new process is created and launched — `Thread (Isolate)`. This is the only process in which your application will run. 583 | 2. Two queues with `MicroTask` and `Event` are initialized, the queue type is `FIFO` (note: first in first out, i.e. messages that arrived earlier will be processed earlier) 584 | 3. The `main()` function is executed 585 | 4. The `Event Loop` is started. It controls the order of execution of your code, depending on the contents of two queues: `MicroTask` and `Event`. It is an "endless" cycle. 586 | 5. The `Event Loop` checks the `MicroTask` and `Event` with a certain frequency. If there is something in the `MicroTask`, then it is executed before the `Event` queue. 587 | 588 | --- 589 | 590 | ### CustomPaint 591 | `CustomPaint` is a class that creates a "canvas" for drawing. The `paint` method uses `canvas` as arguments, which allows you to draw various shapes 592 | 593 | --- 594 | 595 | ### WidgetsFlutterBinding 596 | `WidgetsFlutterBinding` is a specific implementation of application binding based on the widget infrastructure. In essence, it is the glue connecting the framework and the Flutter engine. The `WidgetsFlutterBinding` consists of many links: `GestureBinding`, `ServicesBinding`, `SchedulerBinding`, `PaintingBinding`, `SemanticsBinding`, `RendererBinding`, `WidgetsBinding`. 597 | 598 | The `scheduleAttachRootWidget` method is a deferred implementation of `attachRootWidget`. This method belongs to `WidgetsBinding`. The description says that it attaches the passed widget to the `renderViewElement` — the root element of the element tree. 599 | 600 | The `scheduleWarmUpFrame` method belongs to `SchedulerBinding` and is used to schedule the frame to start as soon as possible without waiting for the `Vsync` system signal. 601 | 602 | --- 603 | 604 | ### Bindings 605 | ![image](https://user-images.githubusercontent.com/80569772/203303949-aadb037a-c818-4f63-8ad8-67c3812a96ad.png) 606 | 607 | `Bindings` are classes for exchanging data between the `Flutter Framework` and the `Flutter Engine`. Each binding is responsible for processing a set of specific tasks, actions, and events grouped by activity area. 608 | 609 | `BaseBinding` is a basic abstract class, then let`s look at specific implementations of bindings. Among them we will see: 610 | 611 | `ServicesBinding` is responsible for redirecting messages from the current platform to the message data handler (`BinaryMessenger`); 612 | 613 | `PaintingBinding` is responsible for linking to the rendering library. 614 | 615 | `RenderBinding` is responsible for the connection between the rendering tree and the Flutter engine. 616 | 617 | `WidgetBinding` is responsible for the connection between the widget tree and the Flutter engine. 618 | 619 | `SchedulerBinding` — scheduler for the next tasks, such as: 620 | - calls of incoming callbacks that the system initiates in `Window.onBeginFrame` — for example, ticker events and animation controllers; 621 | - calls of continuous callbacks initiated by the `Window.onDrawFrame` system, for example, events for updating the display system after incoming callbacks have worked out; 622 | - post-frame callbacks that are called after continuous callbacks, before returning from `Window.onDrawFrame`; 623 | - non-rendering tasks that must be completed between frames. 624 | 625 | `SemanticsBinding` is responsible for linking the semantics layer and the Flutter engine. 626 | 627 | `GestureBinding` is responsible for working with the gesture subsystem. 628 | 629 | --- 630 | 631 | ### Platform Channels 632 | 633 | ![image](https://user-images.githubusercontent.com/80569772/202891758-b7cc7db9-3b4c-4ce3-9f91-37f9a1a614a1.png) 634 | **(!)** Platform interactions are possible only in the main isolate. This is the isolate that is created when your application is launched. 635 | 636 | The `platform channel` is a two—way communication channel between the dart code and the native, which combines the channel name and codec to encode messages into binary form and back. The calls are asynchronous. Each channel must have a unique identifier. 637 | 638 | `Message channels` are platform channels designed for messaging between native code and a flutter application. 639 | `Message codecs`: 640 | - `BinaryCodec` By implementing identifier mapping in byte buffers, this codec allows you to enjoy the convenience of channel objects in cases where you do not need encoding/decoding. Dart message channels with this codec are of the BasicMessageChannel type. 641 | - `JSONMessageCodec` Works with "JSON-like" values (strings, numbers, boolean values, null, lists of these values and key string maps with this data). Lists and maps are heterogeneous and can be nested inside each other. During encoding, the values are converted to JSON strings and then to bytes using UTF-8. Dart message channels are of the BasicMessageChannel type with this codec. 642 | - `StandardMessageCodec` Works with slightly more generalized values than the JSON codec, also supporting homogeneous data buffers (Uint8List, Int32List, Int64List, Float64List) and maps with non-string keys. Number processing differs from JSON in that Dart integers arrive on the platform as 32- or 64-bit signed integers, depending on the value never as floating-point numbers. The values are encoded in a special, fairly compact and extensible binary format. The standard codec is intended to be the default choice for the communication channel in Flutter. As for JSON, Dart message channels created using the standard codec are of the BasicMessageChannel type. 643 | 644 | `Method channels` are platform channels designed to call native code from a flutter application. 645 | `Method codecs`: 646 | - `StandardMethodCodec` delegates encoding of payload values to `StandardMessageCodec`. Since the latter is extensible, the same can be said about the former. 647 | - `JSONMethodCodec` delegates encoding of payload values to `JSONMessageCodec`. 648 | 649 | `Event channels` are specialized platform channels designed to be used in the case of representing Flutter platform events as a Dart stream. It works like a regular `Stream` 650 | 651 | --- 652 | 653 | ### Build Modes 654 | - `Debug` (`JIT`) for development 655 | - `Release` (`AOT`) to publish the application 656 | - `Profile` (`AOT`) for performance analysis 657 | 658 | --- 659 | 660 | ### Package and Plugin 661 | - `Package` is written only in dart 662 | - `Plugin` uses dart and platform-specific code 663 | 664 | --- 665 | 666 | ### FFI Plugin 667 | - `FFI Plugin` is a plugin that uses [Dart FFI] to write platform-specific parts (https://dart.dev/guides/libraries/c-interop ). Allows you to run code in C/C++ 668 | 669 | --- 670 | 671 | ### Animation stages 672 | - `Ticker` asks `SchedulerBinding` to register a callback and tell `Flutter Engine` to wake it up when a new callback appears. 673 | - When the `Flutter Engine` is ready, it calls `SchedulerBinding` via the `onBeginFrame` request. 674 | - `SchedulerBinding` accesses the list of `ticker` callbacks and executes each of them. 675 | - Each `tick` is intercepted by the "interested" controller to process it. 676 | - If the animation is completed, then `ticker` is "disabled", otherwise `ticker` requests `SchedulerBinding` to schedule a new callback. 677 | - ... 678 | 679 | --- 680 | 681 | ### Types of animations 682 | - `Tween animation`. The beginning, the end, the time, the speed are determined in advance 683 | - `Physics-based animation`. Imitate real behavior 684 | 685 | --- 686 | 687 | ### What is a Tween 688 | A `Tween` is an object that describes between which values the widget is animated and is responsible for calculating the current animation value 689 | 690 | --- 691 | 692 | ### Tween animations 693 | - `Implicit Animations` is a set of `Implicitly Animated Widgets` that animate themselves when they are rebuilt with new arguments. (`AnimatedAlign`, `AnimatedContainer`, `AnimatedPadding`, etc.) 694 | - `Explicit Animations` is a set of animation effects controls. They provide much more control over animation than `Implicit Animations`. To use it, you need to mix `SingleTickerProviderStateMixin` / `TickerProviderStateMixin` to the state of your widget, create an `AnimationController` and `Animation` depending on it, pass the animation to the `Transition Widget` (`AlignTransition`, `DecoratedBoxTransition`, `SizeTransition`, etc.) 695 | `SingleTickerProviderStateMixin` / `TickerProviderStateMixin` creates ` Ticker` 696 | `Ticker` calls a callback for each animation frame 697 | `AnimationController` calculates all animation frames - controls animation (forward, reverse, repeat, stop, reset, etc.) 698 | `Animation` gives the current animation value, and also allows you to subscribe to animation value/status updates 699 | 700 | --- 701 | 702 | ### Frame construction 703 | 1. Some external events lead to the need to update the display. 704 | 2. The `Schedule Frame` is sent to the `Flutter Engine` 705 | 3. When the `Flutter Engine` is ready to start updating the rendering, it creates a `Begin Frame` request 706 | 4. This `Begin Frame` request is intercepted by the `Flutter Framework`, which performs tasks related mainly to `Tickers` (for example, animation) 707 | 5. These tasks may re-create the request for later rendering (example: the animation has not finished its execution, and it will need to get another `Begin Frame` at a later stage to complete it) 708 | 6. Next, the `Flutter Engine` sends a `Draw Frame`, which is intercepted by the `Flutter Framework`, which will look for any tasks related to updating the layout in terms of structure and size 709 | 7. After all these tasks are completed, he moves on to tasks related to updating the layout in terms of rendering 710 | 8. If there is something on the screen that needs to be drawn, then a new scene for visualization is sent to the `Flutter Engine`, which will update the screen 711 | 9. Then the `Flutter Framework` performs all the tasks that will be performed after the rendering is completed (`PostFrame callbacks`), and any other subsequent tasks that are not related to rendering 712 | 10. … 713 | 714 | --- 715 | 716 | ### Layout calculation 717 | - Restrictions go down the tree, from parents to children. 718 | - Sizes go up the tree from children to parents. 719 | - Parents determine the position of the children. 720 | 721 | --- 722 | 723 | ### BuildOwner 724 | `BuildOwner` is the manager for building and updating the element tree. He is actively involved in two phases — assembly and completion of assembly. Since the `BuildOwner` manages the tree assembly process, it stores lists of inactive items and lists of items that need updating. 725 | Methods: 726 | - `scheduleBuildFor` makes it possible to mark an item as in need of updating. 727 | - `LockState` protects the element from misuse, memory leaks and marking for updates during the destruction process. 728 | - `buildScope` performs the reassembly of the tree. It works with items that are marked as in need of updating. 729 | - `finalizeTree` completes the construction of the tree. Removes unused elements and performs additional checks in debugging mode, including for duplicating global keys. 730 | - `reassemble` ensures the operation of the `HotReload` mechanism. This mechanism allows you not to rebuild the project with changes, but to send a new version of the code to `DartVM` and initiate a tree update. 731 | 732 | --- 733 | 734 | ### PipelineOwner 735 | `PipelineOwner` is an assembly manager that works with the display tree. 736 | 737 | --- 738 | 739 | ### Garbage Collector 740 | The `Garbage Collector` is an algorithm that monitors links and cleans up memory in order to prevent it from overflowing. 741 | 742 | **(!)** During the garbage collection process, the Dart Framework layer creates a channel of interaction with the Flutter Engine layer, through which it learns about the moments of application downtime and lack of user interaction. At these moments, the `Dart Framework` starts the memory optimization process, which reduces the impact on the user experience and stability of the application. 743 | 744 | **Young garbage collector** 745 | ![image](https://user-images.githubusercontent.com/80569772/203299873-834979fb-a548-476a-8f69-8be50c7ebd64.png) 746 | 747 | The amount of memory used can be divided into two spaces: active and inactive. New objects are located in the active part, where, as it fills up, live objects are transferred from the active memory area to the inactive one, ignoring dead objects. Then the inactive half becomes active. This process is cyclical. 748 | 749 | **Old garbage Collector (Parallel Marking and Concurrent Sweeping)** 750 | ![image](https://user-images.githubusercontent.com/80569772/203300039-95a12d39-d502-4064-8a31-e903407fa04a.png) 751 | 752 | 1. The object tree is traversed, the objects used are marked with a special label. 753 | 2. During the second stage, a repeated pass through the object tree occurs, during which the objects that were not marked in the first stage are processed 754 | 3. All labels are erased 755 | 756 | --- 757 | 758 | ### Task Runners 759 | ![image](https://user-images.githubusercontent.com/80569772/211004726-1eeef86f-cebf-41de-8bb3-a8485257565f.png) 760 | - `Platform Task Runner`: The main flow of the platform. The plugin code is executed here. For more information, see the UIKit documentation for iOS or the MainThread documentation for Android. This thread is not displayed in the performance overlay. 761 | - `UI Task Runner`: The UI thread executes the Dart code in the Dart VM. This stream includes code written by you and code executed by the Flutter framework on behalf of your application. When your application creates and displays a scene, the UI thread creates a layer tree, a lightweight object containing device-independent drawing commands, and sends the layer tree to the raster stream for display on the device. Do not block this stream! Shown in the bottom row of the performance overlay. 762 | - `Raster Task Runner`: The raster stream receives the layer tree and displays it by accessing the GPU (GPU). You cannot directly access the raster stream or its data, but if this stream is slow, then this is the result of what you did in the Dart code. The graphics libraries Skia and Impeller work in this stream. They are shown in the top row of the performance overlay. Previously, this stream was known as the "GPU stream" because it performs rasterization for the GPU. However, it is executed on the central processor. We renamed it the "raster stream" because many developers mistakenly (but quite reasonably) believed that this stream runs on the GPU. 763 | - `IO Task Runner`: Performs expensive tasks (mainly I/O) that would otherwise block the operation of UI threads or raster threads. This stream is not displayed in the performance overlay. 764 | 765 | [More details](https://www.programmersought.com/article/81813680395 /), [More details 2](https://medium.com/flutter-community/the-layer-cake-widgets-elements-renderobjects-7644c3142401 ) 766 | 767 | 768 | ## Architecture 769 | 770 | ### Architecture 771 | Architecture is a set of solutions for the organization of a program. Such as dividing the program into layers, building links between them, managing the state, and communicating with the UI. A good architecture makes the layers in the application loosely connected, which makes it easier to make changes, increases the testability of the code, and simplifies the system 772 | 773 | --- 774 | 775 | ### Clean architecture 776 | Pure architecture is an architecture that follows `SOLID` and is divided into three independent layers: 777 | - `Data (datasources, models, repositories)` getting data from the outside 778 | - `Domain (entities, repositories interfaces, usecases)` business rules 779 | - `Presentation (bloc, pages, widgets)` display 780 | 781 | [Example](https://github.com/ResoCoder/flutter-tdd-clean-architecture-course ) 782 | 783 | --- 784 | 785 | ### State Management 786 | 787 | **Vanilla** 788 | 789 | `Advantages` 790 | - Low entry threshold. 791 | - No third-party libraries are required. 792 | 793 | `Cons` 794 | - When the widget state changes, the widget tree is completely recreated each time. 795 | - Violates the principle of sole responsibility. The widget is responsible not only for creating the UI, but also for loading data, business logic, and state management. 796 | - Decisions on how to display the current state are made directly in the UI code. If the condition becomes more complex, then the readability of the code will decrease significantly. 797 | 798 | `Usage:` 799 | - Widget State 800 | 801 | **BLoC** 802 | 803 | `Advantages` 804 | - Clear division of responsibility 805 | - Predictable Event to State transformations 806 | - Reactivity. There is no need to call additional methods 807 | 808 | `Cons` 809 | - Mandatory status in the Block 810 | - Frequent library changes 811 | - Dependence on a third-party library 812 | 813 | `Usage:` 814 | - Widget State 815 | - App State 816 | 817 | **Redux** 818 | 819 | `Advantages` 820 | - Unified state 821 | - All actions are available to everyone 822 | 823 | `Cons` 824 | - Unified state 825 | - Dependence on a third-party library 826 | - A large amount of boilerplate code 827 | - All actions are available to everyone 828 | 829 | `Usage:` 830 | - Widget State 831 | - App State 832 | 833 | **Provider** 834 | 835 | `Advantages` 836 | - Scopes for subtrees 837 | - Flutter is oriented 838 | - There is no static 839 | - Ready-made providers 840 | 841 | `Cons` 842 | - Link to the framework 843 | - Only 1 provider of the same type 844 | - Dependence on a third-party library 845 | 846 | `Usage:` 847 | - App State 848 | - Partially DI 849 | 850 | **Riverpod** 851 | 852 | `Advantages:` 853 | - Scopes for subtrees 854 | - Flutter is oriented 855 | - There is no static 856 | - Ready-made providers 857 | 858 | `Cons:` 859 | - Dependence on a third-party library 860 | - Cyclic dependencies fall in runtime 861 | 862 | `Usage:` 863 | - Widget State 864 | - App State 865 | - DI 866 | 867 | --- 868 | 869 | ### Dependency Injection 870 | `Dependency injection (DI)` is a mechanism that allows you to make objects interacting in an application loosely coupled using interfaces. This makes the entire system more flexible, adaptable and extensible. 871 | 872 | --- 873 | 874 | ### Architectural patterns 875 | ![](https://fuzeservers.ru/wp-content/uploads/2/6/8/268a107e69309f0529c18aae72769bdb.png) 876 | **MVVM** 877 | 878 | `Parts:` 879 | - `Model` contains all the logic of the application, it stores and processes data, while not interacting with the user directly 880 | - `View` displays the data that was passed to it 881 | - `ViewModel` binds the model and the view (transfers data between them) 882 | 883 | `Usage:` 884 | - Used in a situation where data binding is possible without the need to enter special presentation interfaces (i.e. there is no need to implement IView); 885 | - WPF technology is a common example. 886 | 887 | [Example](https://github.com/jitsm555/Flutter-MVVM ) 888 | 889 | **MVC** 890 | 891 | `Parts:` 892 | - `Model` contains all the logic of the application, it stores and processes data, while not interacting with the user directly 893 | - `View` displays the data that was passed to it 894 | - The `Controller` intercepts the event from the outside and, in accordance with the logic embedded in it, reacts to this event by changing the Model by calling the appropriate method. After the change, the Model uses the event that it has changed, and all subscribed to this View events, upon receiving it, access the Model for updated data, after which they are displayed 895 | 896 | `Usage:` 897 | - Used in a situation where data binding is not possible (Binding cannot be used); 898 | 899 | [Example](https://github.com/flutter-devs/Flutter_MVC ) 900 | 901 | **MVP** 902 | 903 | `Parts:` 904 | - `Model` contains all the logic of the application, it stores and processes data, while not interacting with the user directly 905 | - `View` displays the data that was passed to it 906 | - `Presenter` subscribes to presentation events, modifies the model on request, updates the view 907 | 908 | `Usage:` 909 | - Used in a situation where communication between the view and other parts of the application is not possible (and you cannot use MVVM or MVP); 910 | 911 | --- 912 | 913 | ### Ways to navigate 914 | **Navigator** 915 | - It comes out of the box 916 | 917 | **Go Router** 918 | - Parsing of the path and query parameters (for example, "user/:id") 919 | - Deep-links support 920 | - Redirection support - you can redirect the user to another URL depending on the state of the application 921 | - Named routes 922 | 923 | **Auto Route** 924 | - Parsing of the path and query parameters (for example, "user/:id") 925 | - Deep-links support 926 | - Protected routes 927 | - Named routes 928 | - Different animation options 929 | 930 | --- 931 | 932 | ### Databases 933 | **Non-relational (NoSQL):** 934 | **Hive** 935 | 936 | `Advantages:` 937 | - Implementation on pure Dart, without platform code, due to which it works equally on different platforms 938 | - Easy to use 939 | - Fast write/read 940 | - Little boilerplate code 941 | - Availability of code generation 942 | - Supported on all platforms 943 | 944 | `Cons:` 945 | - Links between objects must be maintained manually 946 | - The limit on the number of adapters for objects is 224 947 | - The limit on the number of fields in the adapter is 255 948 | - Poorly suited for working with a large amount of data 949 | - Uploads the entire database to memory 950 | - You cannot access a box created in another isolate 951 | - Availability of code generation 952 | - There are no migrations 953 | 954 | `Usage:` 955 | - Small amount of data 956 | - The need to save your data models 957 | 958 | **Shared Preferences** 959 | 960 | `Advantages:` 961 | - Easy to use 962 | - Synchronous reading from the in-memory cache 963 | - Supported on all platforms 964 | 965 | `Cons:` 966 | - Different implementations for Android/iOS and other platforms 967 | - Accessing the platform code 968 | - It is not guaranteed to write to disk after successful execution of the method 969 | - It is impossible to save complex objects out of the box 970 | 971 | `Usage:` 972 | - Small amount of data 973 | - The need for rapid implementation of the solution 974 | - Saving application settings as primitive data 975 | 976 | **Relational (SQL):** 977 | **SQFLite** 978 | 979 | `Advantages` 980 | - There are migrations 981 | - Supports connections between entities 982 | - Does not unload the database into RAM 983 | - The ability to write complex SQL queries 984 | 985 | `Cons:` 986 | - Difficult to use 987 | - Not supported on Web, Linux, Windows 988 | - The speed of operation is lower than that of NoSQL 989 | - There may be different versions of SQLite on different OS and versions 990 | 991 | `Usage:` 992 | - Large amount of data 993 | - Storage of complex structured data 994 | 995 | **Drift** 996 | - There are migrations 997 | - Supports connections between entities 998 | - Does not unload the database into RAM 999 | - The ability to write complex SQL queries 1000 | 1001 | `Advantages` 1002 | - There are migrations 1003 | - Fast 1004 | - Supported on all platforms 1005 | 1006 | `Cons:` 1007 | - Difficult to use 1008 | - The speed of operation is lower than that of NoSQL 1009 | 1010 | `Usage:` 1011 | - Large amount of data 1012 | - Storage of complex structured data 1013 | 1014 | 1015 | ## Testing 1016 | 1017 | 1018 | ### Types of tests 1019 | - A `unit test` tests a single function, method, or class. Its purpose is to check the correctness of a certain function, method, or class. External dependencies for the module under test are usually passed as a parameter. 1020 | - `Widget test` tests one widget. The purpose of such a test is to make sure that the widget`s user interface looks and interacts as planned. Widget testing takes place in a test environment that provides the context of the widget`s lifecycle. Also, the widget under test should be able to receive user actions and events and respond to them. 1021 | - The `integration test` tests the entire application or most of it. The purpose of the integration test is to make sure that all tested widgets and services work together as expected. In addition, you can use integration tests to check the performance of your application. As a rule, the integration test is performed on a real device or emulator. 1022 | 1023 | --- 1024 | 1025 | ### TDD 1026 | `TDD` is an application development technique in which first a test is written covering the desired change, and then the code that will allow the test to pass. 1027 | 1028 | 1029 | ## Development patterns 1030 | *Generative*. They are responsible for convenient and safe creation of new objects or even entire families of objects. 1031 | - Factory Method. A generative design pattern that defines a common interface for creating objects in a superclass, allowing subclasses to change the type of objects being created. 1032 | - Abstract Factory (Abstract Factory). A generative design pattern that allows you to create families of related objects without being tied to specific classes of objects being created. 1033 | - Builder (Builder). A generative design pattern that allows you to create complex objects step by step. The builder makes it possible to use the same construction code to get different representations of objects. 1034 | - Prototype. A generative design pattern that allows you to copy objects without going into the details of their implementation. 1035 | - Singleton (Single). A generative design pattern that ensures that a class has only one instance and provides a global access point to it. 1036 | 1037 | *Structural*. They are responsible for building user-friendly class hierarchies. 1038 | - Adapter (Adapter). A structural design pattern that allows objects with incompatible interfaces to work together. 1039 | - Bridge. A structural design pattern that divides one or more classes into two separate hierarchies — abstraction and implementation, allowing them to be changed independently of each other. 1040 | - Composite (Linker). A structural design pattern that allows you to group many objects into a tree structure, and then work with it as if it were a single object. 1041 | - Decorator (Decorator). A structural design pattern that allows you to dynamically add new functionality to objects by wrapping them in useful "wrappers". 1042 | - Facade. A structural design pattern that provides a simple interface to a complex class system, library, or framework. 1043 | - Flyweight (Lightweight). A design pattern that allows you to fit more objects into the allocated RAM. Lightweight saves memory by sharing the general state of objects among themselves, instead of storing the same data in each object. 1044 | - Proxy (Deputy). A structural design pattern that allows you to substitute special substitute objects instead of real objects. These objects intercept calls to the original object, allowing you to do something before or after transferring the call to the original. 1045 | 1046 | * Behavioral*. They solve the tasks of effective and safe interaction between the objects of the program. 1047 | - Chain of Responsibility. A behavioral design pattern that allows requests to be passed sequentially through a chain of handlers. Each subsequent handler decides whether it can process the request itself and whether it is worth passing the request further down the chain. 1048 | - Command (Command). A behavioral design pattern that turns requests into objects, allowing you to pass them as arguments when calling methods, queue requests, log them, and support the cancellation of operations. 1049 | - Iterator (Iterator). A behavioral design pattern that makes it possible to consistently bypass the elements of composite objects without revealing their internal representation. 1050 | - Mediator. A behavioral design pattern that allows you to reduce the connectivity of many classes to each other by moving these relationships into one intermediary class. 1051 | - Memento (Snapshot). A behavioral design pattern that allows you to save and restore the past states of objects without revealing the details of their implementation. 1052 | - Observer (Observer). A behavioral design pattern that creates a subscription mechanism that allows one object to monitor and respond to events occurring in other objects. 1053 | - State. A behavioral design pattern that allows objects to change behavior depending on their state. From the outside, it seems that the class of the object has changed. 1054 | - Strategy. A behavioral design pattern that defines a family of similar algorithms and places each of them in its own class, after which the algorithms can be interchanged right during program execution. 1055 | - Template Method (Template Method). A behavioral design pattern that defines the skeleton of an algorithm, shifting responsibility for some of its steps to subclasses. The pattern allows subclasses to redefine the steps of the algorithm without changing its overall structure. 1056 | - Visitor. A behavioral design pattern that allows you to add new operations to the program without changing the classes of objects on which these operations can be performed. 1057 | 1058 | [More details](https://refactoring.guru/en/design-patterns/catalog ) 1059 | --------------------------------------------------------------------------------