├── 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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
755 |
756 | Используемый объём памяти можно разделить на два пространства: активное и неактивное. Новые объекты располагаются в активной части, где по мере её заполнения, живые объекты переносятся из активной области памяти в неактивную, игнорируя мёртвые объекты. Затем неактивная половина становится активной. Этот процесс имеет цикличный характер.
757 |
758 | **Сборщик старого мусора (Parallel Marking and Concurrent Sweeping)**
759 | 
760 |
761 | 1. Осуществляется обход дерева объектов, используемые объекты помечаются специальной меткой.
762 | 2. Во время второго этапа происходит повторный проход по дереву объектов, в ходе которого непомеченные в первом этапе объекты перерабатываются
763 | 3. Все метки стираются
764 |
765 | [Подробнее](https://habr.com/ru/company/rshb/blog/668600/)
766 |
767 | ---
768 |
769 | ### Task Runners
770 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 |
--------------------------------------------------------------------------------