Это вторая часть серии статей об архитектуре Android-приложения Bright.money. В нем мы подробно поговорим о том, что такое архитектура ELM. В связи с тем, что наша реализация доступна в открытом исходном коде в виде библиотеки Элмсли , в статье будет использовано название из него.
Оглавление
- Первая часть.
Как мы выбрали архитектуру презентационного слоя на новом проекте и не прогадали.
- Часть вторая.
Давайте проанализируем архитектуру ELM в мобильном приложении.
- Часть третья.
Пишем для Android с Элмсли.
Введение
Одной из основных проблем при разработке мобильных приложений с использованием шаблонов MVP/MVVM/MVC является раздуваться ведущие.Зачастую они содержат абсолютно все управление асинхронной работой и состоянием приложения.
С течением времени логика усложняется, а общая кодовая база разрастается, их становится невероятно сложно изменить.
А понять, что происходит в презентере, написанном другим разработчиком, может стать непосильной задачей, а исправление ошибок только вносит новые ошибки.
Архитектуры однонаправленных потоков данных были разработаны для решения этой задачи.
Первое решение для Android было описано более 4 лет назад (!) Ханнесом Дорфманом в статья о МВИ для Android. Помимо MVI, самого популярного представителя однонаправленных архитектур в мобильном сообществе, есть и другие.
В этой статье мы остановимся на архитектуре, которую мы используем — ELM.
О чем эта статья?
Архитектура ELM — достаточно общее решение, имеющее множество применений.Однако для упрощения понимания опишем это на примере реализации уровня представления.
Как только вы поймете поведение архитектуры на простом примере, вы сможете искать другие приложения.
Место ELM в архитектуре Представьте, что мы проектируем архитектуру с нуля.
Конечно, на момент написания статьи результат уже известен.
В любой момент времени могло быть принято другое решение, могли быть выделены другие детали или проблема могла быть решена по-другому.
Такой способ изложения был выбран исключительно для упрощения понимания.
В описании мы не будем останавливаться на модели, поговорим о том, как писать бизнес-логику, делать запросы к API. Об организации кода во View тоже не будет ни слова; эти пункты оставляются на ваше усмотрение.
Слой внешнего вида
Когда мы рассматриваем уровень представления в контексте разработки мобильных приложений, мы представляем экраны и способы их написания.Архитектура описывает, как построить реализацию с одним экраном.
Попробуем сформулировать набор требований к тому, как будет организовано взаимодействие с презентационным слоем одного экрана в общем случае.
Основным компонентом ELM является одна сущность — Магазин .
В простой версии весь уровень представления описывается одной сущностью.
В более сложных случаях экран может состоять из нескольких Магазин , но об этом мы поговорим в одной из следующих статей.
Попробуем описать свойства Магазин :
Требования к уровню представления Любой уровень представления должен взаимодействовать с моделью.
Нам придется обрабатывать бизнес-логику, делать запросы к API, сохранять данные в кеш и так далее.
Давайте изобразим это как возможность.
Магазин получить доступ к модели, получить из нее данные и выполнить операции.
Взаимодействие Вид это немного сложнее.
Он состоит из трех компонентов:
- В пользовательском интерфейсе происходят события — нажатия кнопок, прокрутка списка, обновление по запросу и другие.
Давайте позвоним им Событие.
UI .
- Экран имеет некоторое состояние.
Сюда может входить информация о том, отображается ли в данный момент статус загрузки, данные, которые будут отображаться в списке, или текущее положение тумблера.
Давайте включим все это в термин Состояние .
- Уровень представления не только имеет состояние, но также может выдавать команды просмотра.
Например, вам нужна возможность показать Toast, Snackbar или перейти на другой экран.
Все это невозможно описать в Состояние , поскольку он хранит информацию и требует некоторых действий для ее представления.
Для этого выделим отдельную сущность — Эффект .
И теперь внутри
В предыдущем разделе мы описали поведение Магазин со стороны, как это выглядит для стороннего наблюдателя или пользователя.Теперь попробуем описать, что происходит внутри него:
- Обработка событий в пользовательском интерфейсе ( Событие.
UI
) - Изменение состояния экрана ( Состояние )
- Запуск операций в пользовательском интерфейсе ( Эффект )
- Получение данных из модели
- Выполнение операций над моделью
- Сложные расчеты
Работа на разделенном экране Опишем сущности, которые у нас получились:
Актер
Схема работы актера В Актер Размещены все асинхронные операции, расчеты и работа с моделью.
Опишем это, используя Команда , который вообще запускает какую-то операцию и Событие который вернет результат этой операции.
Например:
- Подпишитесь на обновление данных в модели
- Делаем запрос API
- Запуск таймера для выполнения операции
Редуктор
Как работает Редуктор По сути в Редуктор все осталось логика работа экрана.
Он знает о текущем состоянии экрана, узнает о происходящих событиях и рассчитывает реакция на них.
События могут поступать из пользовательского интерфейса и из Актер , в результате операции.
Реакция состоит из Эффект - команды для пользовательского интерфейса, Состояние текущее состояние, которое будет отображено на экране и Команда - начать операцию в Актер Например:
- В Событие - нажмите на кнопку скачать Состояние флаг будет отображаться isLoading на истинный и оно начнется Команда - сделать запрос к API
- В Событие - произошла ошибка при загрузке данных в Состояние флаг будет отображаться isLoading В ЛОЖЬ и пойду Эффект - показать ошибку в пользовательском интерфейсе
Его можно представить как чистая функция.
То есть функция, которая не создает побочных эффектов и всегда выдает один и тот же результат для одних и тех же входных данных.
Результат
Компоненты Результат Давайте также выберем отдельную сущность, которая будет представлять ту же самую реакция Редуктор на Событие и давай позвоним ей Результат. Это состоит из:
- Эффект - команды для пользовательского интерфейса
- Состояние - текущее состояние экрана
- Команда - команды для запуска операций в Актер
Собираем все это вместе
Если объединить все эти компоненты, то получится примерно следующая картина:Внутри магазина Вид И Актер являются источниками событий.
Это представлено как Событие .
События разделены по типу источника, например Вид Этот Событие.
UI , и для Актер Этот Событие.
Внутреннее .
События вызывают изменения состояния экрана, отдельные эффекты и запуск асинхронных операций.
Состояние экрана представлено State, которое передается в представление для рендеринга.
Единичные эффекты обозначаются как Эффект и обрабатываются одинаково Вид .
Актер в свою очередь работает с моделью, запускает операции и получает от нее данные.
А Магазин связывает все это вместе.
Как это работает?
Следующие GIF-диаграммы схематически иллюстрируют работу простого экрана.Слева UI, в центре то, что происходит в ELM, справа текущее Состояние экран.
Скрипт успешной загрузки
Давайте рассмотрим сценарий, в котором при нажатии кнопки значение успешно загружается и отображается в пользовательском интерфейсе.
Работа ELM при успешном сценарии
- Пользователь нажимает кнопку «Обновить».
- Пользовательский интерфейс отправляет Событие.
UI
назначенный НАЖМИТЕ - НАЖМИТЕ доходит до Редуктор
- Результат работы Редуктор становится изменением isLoading на истинный В Состояние и отправка Команда обозначен как НАГРУЗКА
- Из-за изменения Состояние текст рисуется в пользовательском интерфейсе ЗАГРУЗКА.
- В Актер выполненный Команда загрузка данных - НАГРУЗКА
- Результат выполнения команды: Событие.
Внутреннее
со смыслом ЦЕНИТЬ - Редуктор обрабатывает событие ЦЕНИТЬ и изменения в Состояние возле поля ценить стоимость на 123 , и возле поля isLoading на ЛОЖЬ
- Текст рисуется в пользовательском интерфейсе ЗНАЧЕНИЕ = 123 Сценарий неудачной загрузки
И теперь безуспешно
Давайте рассмотрим сценарий, когда при нажатии на кнопку значение не может быть загружено, после чего Snackbar отображается с ошибкой.
Работа ELM в случае ошибки
- Пользователь нажимает кнопку еще раз Перезагрузить и идет Событие.
UI
назначенный НАЖМИТЕ - НАЖМИТЕ доходит до Редуктор
- Результат работы Редуктор становится изменением isLoading на истинный В Состояние и отправка Команда обозначен как НАГРУЗКА
- Из-за изменения Состояние текст рисуется в пользовательском интерфейсе ЗАГРУЗКА.
- В Актер выполненный Команда загрузка данных - НАГРУЗКА
- Результат выполнения команды: Событие.
Внутреннее
со смыслом ОШИБКА - Редуктор обрабатывает событие ОШИБКА и изменения в Состояние значение поля isLoading на ЛОЖЬ а также отправляет Эффект уполномоченный ОШИБКА
- ручки пользовательского интерфейса Эффект назначенный ОШИБКА и показывает Snackbar с ошибкой
В конце концов
Архитектура ELM пришла из Интернета и пока не так популярна в мобильном сообществе.Однако он определенно заслуживает внимания, наряду с более привычным MVI, благо отличий между ними не так уж и много.
По сравнению с популярными MVP и MVVM его легче тестировать, он позволяет писать более простой код и лучше масштабируется.
Подробнее о причинах нашего выбора ELM-архитектуры мы говорили в предыдущий части сериала.
Поскольку существующие реализации ELM показались нам недостаточно лаконичными и простыми в использовании, мы создали Элмсли .
Мы постарались вобрать в себя преимущества существующих реализаций, максимально упростив написание кода.
В следующей части мы поговорим о том, как использовать нашу библиотеку.
Теги: #Android #Разработка Android #программирование #архитектура #разработка мобильных устройств #Kotlin #архитектура приложений #дизайн и рефакторинг #архитектура mvi #mvi #elm #vivid.money #udf
-
Формализация Общения В Социальных Сетях
19 Dec, 24 -
Количество Патентов Бьет Все Рекорды
19 Dec, 24 -
Дайджест Игровой Индустрии: Март
19 Dec, 24 -
Плагин Imglikeopera В Firefox 3 Rc
19 Dec, 24 -
Эксперты Bybanner.com
19 Dec, 24 -
Зимний Дайджест Новостей Игровой Индустрии
19 Dec, 24