1. Введение в архитектуру: жизненный цикл, проблемы монолита и паттерны MVC, MVP
Введение в архитектуру: жизненный цикл, проблемы монолита и паттерны MVC, MVP
Добро пожаловать в курс «Архитектура Android-приложений». Если вы когда-либо открывали проект, видели класс MainActivity на 3000 строк кода и испытывали желание немедленно закрыть ноутбук, то вы попали по адресу.
В этой первой статье мы разберем фундамент: почему в Android вообще нужна архитектура, как жизненный цикл компонентов усложняет нам жизнь, и рассмотрим первые попытки сообщества структурировать код с помощью паттернов MVC и MVP.
Почему архитектура важна?
Когда вы пишете небольшое приложение «Hello World» или простой калькулятор, архитектура кажется излишеством. Вы пишете логику прямо в методе onCreate, обращаетесь к базе данных по нажатию кнопки и обновляете UI там же. Это работает.
Но по мере роста приложения возникают проблемы:
Архитектура — это не просто красивые диаграммы. Это способ организовать код так, чтобы стоимость его поддержки не росла экспоненциально со временем.
Проклятие жизненного цикла Android
Главное отличие разработки под Android от, скажем, бэкенда или десктопа — это Жизненный цикл (Lifecycle). В Android вы не управляете точкой входа в приложение (main()). Система сама решает, когда создать, остановить или уничтожить ваш экран.
Проблема поворота экрана
Представьте сценарий: пользователь заполняет форму регистрации и поворачивает экран. Что происходит?
Activity.Activity с новой конфигурацией (ландшафтная ориентация).Activity теряются.Если ваша бизнес-логика (например, сетевой запрос) находится прямо внутри Activity, то при повороте экрана запрос либо прервется, либо, что хуже, вернет результат в уже уничтоженную Activity, вызвав утечку памяти или краш (Crash).
God Object и спагетти-код
Если не использовать архитектурные паттерны, мы получаем так называемый Monolith или God Activity.
Это класс, который знает и умеет слишком много: * Он управляет UI (отображает кнопки, списки). * Он ходит в сеть (Retrofit/OkHttp). * Он пишет в базу данных (Room/SQLite). * Он содержит сложную бизнес-логику (валидация, расчеты).
Пример такого подхода:
Такой код невозможно тестировать (как вы сымитируете клик кнопки в Unit-тесте?) и очень сложно читать. Чтобы решить эту проблему, разработчики начали применять паттерны разделения ответственности.
MVC: Model-View-Controller
Один из старейших паттернов, пришедший из мира веба и десктопа.
Классическая теория
* Model (Модель): Данные и бизнес-логика (База данных, API, сущности). * View (Представление): Отображение данных пользователю (UI). * Controller (Контроллер): Принимает ввод от пользователя и обновляет Модель.
MVC в Android
В ранней Android-разработке попытка применить MVC выглядела так:
* Model: Ваши Java/Kotlin классы данных.
* View: XML-файлы разметки.
* Controller: Activity или Fragment.
Однако, это разделение оказалось фикцией. Activity в Android — это не чистый контроллер. Она слишком сильно связана с UI. Она знает, как найти кнопку (findViewById), как установить текст, как обработать анимацию. В итоге Activity становилась и Контроллером, и Представлением одновременно.
Проблемы MVC в Android:
Activity все еще остается Божественным объектом.MVP: Model-View-Presenter
Чтобы решить проблему «толстой» Activity и сделать код тестируемым, появился паттерн MVP. Это была первая настоящая революция в архитектуре Android-приложений.
Главная идея: Полностью отделить логику от Android-фреймворка.
Компоненты MVP
Контракт (Contract)
Ключевая особенность MVP — использование интерфейсов (Контракта) для связи между View и Presenter. Это разрывает жесткую зависимость.
Пример контракта:
Реализация Presenter
Обратите внимание: в коде Presenter нет ни одного импорта из пакета android.*. Это чистый Kotlin/Java код.
Реализация View (Activity)
Activity теперь становится «глупой». Она просто реализует интерфейс.
!Presenter выступает посредником, изолируя View от Model и бизнес-логики.
Преимущества MVP
Presenter не зависит от android.content.Context или android.view.View, мы можем легко написать Unit-тесты, подменив View моком (Mock).Недостатки MVP
view = null), иначе будет утечка памяти или краш при попытке вызвать метод у уничтоженной Activity.Заключение
MVP был золотым стандартом Android-разработки долгое время. Он научил разработчиков разделять UI и логику. Однако необходимость вручную управлять жизненным циклом и обилие шаблонного кода привели к поиску новых решений.
В следующей статье мы рассмотрим паттерн MVVM (Model-View-ViewModel), который стал официальной рекомендацией Google и решил многие проблемы MVP благодаря реактивному подходу и Architecture Components.