Практика 14. Практическая работа 14. Платформенные архитектуры и жизненный цикл (Android/iOS)
Раздел 2. Привязка к лекции 14. Работа аналитическая/проектная: разбираем нативные платформы, кода на React Native не пишем. Достаточно описаний, таблиц и псевдокода/последовательностей колбэков.
Цели работы
- Разобраться в платформенных архитектурах мобильных приложений: MVVM, MVI, Clean — кто за что отвечает и как течёт данные.
- Понять и описать жизненный цикл экрана на Android (Activity/Fragment) и iOS (UIViewController), сопоставить аналогичные колбэки.
- Научиться рассуждать о сохранении состояния при повороте экрана, сворачивании и убийстве процесса на каждой платформе.
- Уметь обоснованно выбирать архитектуру под конкретную фичу, а не «по привычке».
Задания
Задание 1. Сравнительная таблица: MVVM / MVI / Clean
Заполните таблицу и кратко прокомментируйте каждую строку своими словами (1–2 предложения).
| Критерий | MVVM | MVI | Clean |
|---|---|---|---|
| Уровень применения | Presentation (экран) | Presentation (экран) | Всё приложение (слои) |
| Участники | View, ViewModel, Model | View, Intent, Reducer, State, эффекты | Domain (UseCase/Entity), Data, Presentation, Framework |
| Состояние | Несколько полей/потоков в VM | Одно неизменяемое State | Не про состояние, а про границы слоёв |
| Поток данных | Двунаправленный: события ⇄ state | Однонаправленный: Intent → Reducer → State | Зависимости направлены внутрь (UI → Domain) |
| Бойлерплейт | Низкий | Высокий | Средний/высокий |
| Дебаг и трассировка | Средний | Отличный (лог интентов, time-travel) | — (ортогонально) |
| Тестируемость | Логика в VM/UseCase | Чистый reducer тестируется легко | Domain без зависимостей — юнит-тесты без устройства |
| Плюсы | Просто, ложится на Compose/SwiftUI | Предсказуемость, единый источник правды | Слабая связность, замена SDK без переписывания домена |
| Минусы | Риск «толстой» VM | Много кода на простых экранах | Накладные расходы на маленьких проектах |
| Когда выбирать | Дефолт для большинства экранов | Сложные состояния, важны дебаг и предсказуемость | Средние/крупные долгоживущие проекты |
Вывод для отчёта: объясните, почему подходы не взаимоисключающие (Clean задаёт слои, MVVM/MVI организуют экран) и приведите пример связки, например Clean + MVVM на уровне экрана.
Задание 2. Жизненный цикл экрана: Android vs iOS
2.1. Android. Опишите последовательность колбэков Activity и дополнительно отметьте специфику Fragment.
Activity: onCreate → onStart → onResume → [экран активен] → onPause → onStop → onDestroyFragment: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume ... onPause → onStop → onDestroyView → onDestroy → onDetachВажно различать жизненный цикл фрагмента и его View: onCreateView/onDestroyView срабатывают чаще, View пересоздаётся, а сам фрагмент может жить дольше.
2.2. iOS. Опишите последовательность колбэков UIViewController.
UIViewController: viewDidLoad → viewWillAppear → viewDidAppear ... viewWillDisappear → viewDidDisappearviewDidLoad вызывается один раз при создании View; viewWillAppear/viewDidAppear — каждый раз при показе экрана.
2.3. Заполните таблицу сопоставления аналогов.
| Назначение | Android | iOS |
|---|---|---|
| Разовая инициализация при создании View | onCreate / onViewCreated | viewDidLoad |
| Экран вот-вот появится | onStart | viewWillAppear |
| Экран стал видимым/активным | onResume | viewDidAppear |
| Экран вот-вот скроется | onPause | viewWillDisappear |
| Экран скрыт | onStop | viewDidDisappear |
| Освобождение ресурсов | onDestroy / onDestroyView | deinit |
В декларативных фреймворках вместо колбэков контроллера используют: Android Compose — эффекты + repeatOnLifecycle; SwiftUI — onAppear/onDisappear и @StateObject/@State, переживающие перерисовку.
Задание 3. Сценарий «поворот / сворачивание / убийство процесса»
Разберите три события и для каждого опишите, что произойдёт с состоянием и как его сохранить. Оформите как таблицу + короткий комментарий.
| Событие | Android: что происходит | Android: как сохранить | iOS: что происходит | iOS: как сохранить |
|---|---|---|---|---|
| Поворот экрана | Activity/Fragment пересоздаётся, локальное состояние теряется | ViewModel переживает поворот; UI-состояние — в ней | Контроллер не пересоздаётся, меняются размеры (viewWillTransition) | Состояние и так живёт в модели/VM, отдельных действий не требуется |
| Сворачивание (фон) | onPause → onStop, объекты живы, но процесс может быть выгружен позже | Тяжёлую работу остановить; данные — в VM/репозитории | viewWillDisappear, приложение в фоне (scenePhase/applicationDidEnterBackground) | Сохранить незавершённый ввод в модель/хранилище |
| Убийство процесса | Всё в памяти теряется, при возврате — новый процесс | SavedStateHandle (+ persistence: БД/файлы) для восстановления | Систему выгрузила приложение из памяти | State Restoration (+ persistence) для восстановления экрана |
Ключевая мысль для отчёта: долговечное состояние нельзя хранить в Activity/Fragment/UIViewController — его выносят в ViewModel/модель/сервис, а для переживания смерти процесса используют сериализуемое хранилище (SavedStateHandle / State Restoration / БД).
Дополнительно: объясните, почему сбор Flow/LiveData нужно делать lifecycle-aware (repeatOnLifecycle(STARTED)) — что произойдёт, если этого не сделать (утечки, фоновая работа).
Задание 4 (дополнительное). Выбор архитектуры под фичу
Выберите одну фичу из списка (или предложите свою) и обоснуйте архитектуру в 5–8 предложениях:
- Экран ленты новостей с пагинацией и pull-to-refresh.
- Сложная форма оформления заказа: 6 шагов, валидации, зависящие поля, отмена/возврат.
- Экран профиля «только чтение» с парой полей.
- Чат реального времени с историей сообщений и индикаторами доставки.
В обосновании укажите: выбранный подход (MVVM/MVI и нужен ли Clean), как организовано состояние, где живёт навигация, как переживается поворот/убийство процесса. Сошлитесь на критерии из Задания 1.
Ориентир: простой экран (п. 3) — MVVM без Clean; сложное состояние с откатами (п. 2, 4) — MVI и, при росте, Clean.
Критерии оценки
| Критерий | Вес |
|---|---|
| Задание 1: таблица заполнена корректно, есть комментарии и вывод о сочетаемости подходов | 30% |
| Задание 2: последовательности колбэков верны, таблица аналогов сопоставлена правильно | 25% |
| Задание 3: разобраны все три события на обеих платформах, верно указаны механизмы сохранения | 25% |
| Задание 4 (доп.): обоснованный выбор со ссылкой на критерии | 10% |
| Аккуратность оформления, терминология, отсутствие путаницы Android/iOS | 10% |
Итого: 100% (Задание 4 даёт до 10% и может компенсировать недочёты в основных).
Вопросы для самопроверки
- Чем MVVM отличается от MVI по управлению состоянием и потоку данных? Когда что выбирать?
- Почему Clean Architecture — это не альтернатива MVVM/MVI, а другой «срез» приложения?
- Чем отличается жизненный цикл фрагмента от жизненного цикла его View в Android?
- Какой колбэк iOS — аналог
onResume, а какой — аналогonCreate? ПочемуviewDidLoadвызывается реже, чемviewWillAppear? - Почему при повороте Android теряет состояние, а iOS — нет? Как это влияет на хранение данных?
- Как восстановить экран после убийства процесса в Android и в iOS соответственно?
- Зачем собирать
Flow/LiveDataчерезrepeatOnLifecycleи что будет без этого? - Где должна жить навигация и почему её не стоит держать во ViewModel?
Ресурсы
- Лекция 14 «Платформенные архитектуры и жизненный цикл (Android/iOS)» — основной материал.
- Android Developers: Guide to app architecture, Lifecycle, ViewModel, SavedStateHandle, Jetpack Navigation.
- Apple Developer: View Controller Programming Guide, Managing Your App’s Life Cycle, State Restoration.
- Jetpack Compose: side-effects,
repeatOnLifecycle; SwiftUI:onAppear/onDisappear,@StateObject,scenePhase. - Материалы по MVI/Redux (связь с лекцией 11) и по Clean Architecture (правило зависимостей внутрь).