Рубрики
Без рубрики

Учебное пособие: чертежи архитектуры Android, полное приложение для выполнения задач (издание MVO)

Мы берем приложение Android Architecture Blueprints todo и переписываем в MVA, используя бесплатную библиотеку. С тегами android, java, для, mvo.

Это часть серии на Android передний

1) Учебное пособие: Определите преднамеренную ошибку
2) Учебное пособие: Android для основ
3) Учебное пособие: Архитектура Android, полное приложение для задач (издание MVO)
4) Учебное пособие: Состояние Android против события
5) Учебное пособие: Сопрограммы Kotlin, модернизация и подготовка

Чертежи Архитектуры Android * продемонстрируйте различные архитектуры Android, реализовав одно и то же приложение типа “дела” несколько раз (по одному разу для каждого варианта архитектуры).

* Обратите внимание, что репозиторий Android Architecture Blueprints теперь отказался от оригинальной версии приложения todo – реализация MVO здесь остается реализацией Java с наименьшим количеством строк кода с довольно большим отрывом.

Я оставляю эту статью, так как она дает довольно хорошее руководство о том, как и почему мы можем отойти от архитектур MVP и перейти к чему-то более управляемому состоянием, такому как MVVM, этот пост делает еще один шаг вперед и реализует полный проект в стиле MVO (вот почему количество кода так резко сократилось). Если после прочтения этого вы захотите чего-то в котлине, то чистая архитектура сообщение – хорошее место, чтобы отправиться дальше – или просто посмотреть любое из очень простых примеров приложений, которые существуют, например, то, которое поставляется с сохраняется библиотека

В этом посте мы добавим еще одну архитектуру: MVO реализован с помощью для .

Наш форк написан на Java, он основан на эталонной реализации MVP.

  • он использует меньше кода, чем любая другая реализация Java (1971 строк, 3261 строк вкл. тесты)
  • версия Kotlin-MVO потребляла бы еще меньше
  • большая часть оставшегося кода была удалена из слоя представления
  • структура приложения, возможно, намного понятнее.

Однако это не идеальное сравнение: наша версия MVO обрабатывает издевательство над сервером по-другому, и мы добавили базовую реализацию Dagger 2 для DI (хотя мы оставили там класс реализации чистого DI, чтобы вы могли сравнить их). Наша версия MVO на самом деле имеет больше функциональности, чем оригинал, мы поддерживаем анимированные изменения списка с помощью DiffUtil, и существует надежная сетевая реализация для извлечения задач из серверной части (некоторые json размещены по адресу mocky.io ) – несмотря на это , он по-прежнему работает с меньшим количеством кода .

Давайте посмотрим, как мы это сделали…

(Примечание: есть много ссылок на Задача в следующем коде в этой ситуации задача означает физическую задачу реального мира, например, рутинную работу или элемент задач. Это не имеет ничего общего с задачей Android или AsyncTask.)

Оригинальная структура пакета MVP

Структура пакета версии MVP слегка смешивает понятия: данные и util не требуют пояснений, но добавить задачу редактирования , статистика , подробная информация о задаче , задачи все относятся к разделам пользовательского интерфейса приложения (они отображаются на экране добавления/редактирования, экране статистики и т. Д.).

Действительно, внутри этих пакетов пользовательского интерфейса мы видим такие элементы пользовательского интерфейса Android, как Действия, Фрагменты, а также обычные классы MVP: Контракт и Ведущий.

Общая структура создает впечатление, что все приложение – это его пользовательский интерфейс (плюс данные и несколько полезных методов). С точки зрения отделения слоя просмотра от остальной части приложения, мы можем сделать намного лучше, чем это.

( Докладчики написаны для конкретных представлений, которыми они управляют, но в большинстве приложений даже в этом небольшом представления представляют собой разные окна для одних и тех же данных, и многое из того, что происходит в классах докладчиков, повторяется в нескольких презентерах. Одна из вещей, которые делает MVO, заключается в том, чтобы переместить этот код ближе к приложению и подальше от конкретных представлений, которые могут захотеть его использовать. Это означает, что его можно написать и протестировать один раз, значительно улучшив DRY и по-прежнему поддерживая несколько более тонких представлений, которые легче изменить. )

Структура пакета MVO

Для реализации MVO мы разделили пакет data на api и бд (полезно разделять эти два параметра, например, это позволяет нам обрабатывать незначительные изменения api, не слишком влияя на нашу модель бд).

Мы оставим пакет util таким, какой он есть – он не является центральным в нашем обсуждении.

сообщение содержит наши глобально применимые сообщения приложений, такие как ERROR_BUSY или ERROR_SESSION_TIMED_OUT – на самом деле мы не хотим, чтобы что-либо за пределами нашего пакета api знало о таких вещах, как коды ошибок HTTP или сетевые исключения. Код в пакете api обрабатывает сопоставление между HTTP и этими сообщениями для нас, не позволяя каким-либо сетевым деталям просачиваться в остальную часть приложения.

Все вышесказанное, на мой взгляд, является хорошей идеей, но не относится конкретно к MVO, хотя следующие два пакета – это то, что действительно определяет структуру MVO: пользовательский интерфейс и особенность

пакет пользовательского интерфейса

Пакет ui – это то место, где вы найдете добавил его , статистика , , подробная информация о задаче и

пакет функций

Теперь перейдем к пакету функций . Если вы представляете приложение существующим само по себе, без привязки к какому-либо конкретному пользовательскому интерфейсу, то основная часть его будет находиться в пакете функций. Это то, что вы сделали бы на уровне домена, если бы хотели назвать вещи в соответствии с чистой архитектурой.

Для этого небольшого приложения есть только одна “функция” – управление задачами/задачами, поэтому здесь есть только один подпакет: задачи . В большинстве коммерческих приложений здесь будет намного больше функций, типичными примерами могут быть такие вещи, как: учетная запись , корзина покупок , избранное , чат , лояльность , входящие , плейлисты и т.д.

Это место, где живут модели в МВО . Это бизнес-логика приложения, и код здесь должен быть прост в модульном тестировании: эти классы должны знать как можно меньше об Android, контекстах и, конечно же, ничего не знать о жизненных циклах фрагментов и т.д. Вы можете обратиться к передним документам для получения полных рекомендаций о том, как писать эти модели – это стандартный совет, который также применим к написанию моделей представлений.

Функция задач

Это существенное переписывание кода, существующего в реализации MVP.

Элемент задачи

Это определение задачи в приложении.

  • Он выглядит похожим, но не таким, как класс task в пакете api , который мы намеренно назвали TaskItemPojo чтобы мы не запутались.

  • Он выглядит похожим, но не таким, как класс задач, найденный в пакете db , который мы намеренно назвали TaskItemEntity , опять же, чтобы мы не путались.

(Это может показаться большим усилием, и вы можете написать один класс задач, который удовлетворяет всем требованиям вашего api, вашей модели базы данных и вашей функции, если хотите – все может усложниться, когда у вас изменяются требования и API, поэтому просто помните о компромиссах здесь)

Вот остальная часть этой функции:

Сборщик задач

Все, что для этого нужно: подключиться к сети, извлечь задачи из бэкэнда и добавить их в локальное хранилище.

Большая часть работы, связанной с подключением к сети: анализ ответов; обработка ошибок; многопоточность и т. Д., Выполняется процессором вызовов CallProcessor , который представляет собой тонкую оболочку поверх модернизации и OkHttp (также есть один для Apollo и один для Ktor). Мы передаем загруженные задачи прямо в tasklistмодель , которая обрабатывает работу с базой данных. Так что все, что нам осталось на этом занятии, – это немного бизнес-логики.

Это наблюдаемо ,

Полный код находится здесь .

Модель списка задач

Этот класс обертывает базу данных и заботится обо всех потоках, так что слою представления не нужно беспокоиться об этом. Любой доступ к базе данных осуществляется здесь, чтобы база данных была прозрачной для остальной части приложения.

Этот класс предназначен для поддержки адаптера Android, поэтому он включает общедоступные методы, такие как size() и get() .

Этот класс также является наблюдаемым , так что все наблюдатели будут проинформированы о любых изменениях в списке задач. Когда мы оборачиваем базу данных комнаты, мы просто подключаемся к собственной комнате Отслеживание недействительности для этого, что прямо аналогично наблюдателям за силами.

Анимированные обновления списка : поскольку мы планируем анимировать изменения в списке задач, мы реализуем здесь изменяемый интерфейс (это небольшой помощник из переднего плана это позволит нам автоматизировать большую часть сложностей, связанных с использованием диффузоров).

Полный код находится здесь .

Текущая Модель Задачи

Этот класс управляет любыми представлениями, связанными с определенной задачей (в настоящее время taskdetail и добавил его ).

Для этого у него есть общедоступные методы, такие как setTitle() , Получить описание() , Сохранить изменения() и т.д.

Как и в случае с другими моделями, она написана с предположением, что все методы будут вызываться в одном потоке. Любая потоковая передача управляется внутренне вне слоя представления.

И снова это можно наблюдать, так что любые наблюдатели знают, когда синхронизировать свой взгляд.

Исправление слоя вида

Теперь мы переходим к самому легкому! Взгляните на некоторые из методов set/show, которые существуют в старом коде слоя представления:

@Override
public void setLoadingIndicator(final boolean active) {
  if (getView() == null) {
    return;
  }
  final SwipeRefreshLayout srl =
    (SwipeRefreshLayout) getView().findViewById(R.id.refresh_layout);

  // Make sure setRefreshing() is called after the layout is done with everything else.
  srl.post(new Runnable() {
    @Override
    public void run() {
      srl.setRefreshing(active);
    }
  });
}

@Override
public void showTasks(List tasks) {
  mListAdapter.replaceData(tasks);
  mTasksView.setVisibility(View.VISIBLE);
  mNoTasksView.setVisibility(View.GONE);
}

@Override
public void showNoActiveTasks() {
  showNoTasksViews(
    getResources().getString(R.string.no_tasks_active),
    R.drawable.ic_check_circle_24dp,
    false
  );
}

Даже для простых пользовательских интерфейсов подобный код может стать очень сложным и привести к незаметным, трудно обнаруживаемым ошибкам в пользовательском интерфейсе. Вот полный список методов, необходимых для поддержки только интерфейса основных задач (обратите внимание, что это всего лишь сигнатуры методов, мы даже не показываем полные методы):

@Override
public void setLoadingIndicator(final boolean active) {...}

@Override
public void showTasks(List tasks) {...}

@Override
public void showNoActiveTasks() {...}

@Override
public void showNoTasks() {...}

@Override
public void showNoCompletedTasks() {...}

@Override
public void showSuccessfullySavedMessage() {...}

private void showNoTasksViews(String mainText, int iconRes, boolean showAddView) {...}

@Override
public void showActiveFilterLabel() {...}

@Override
public void showCompletedFilterLabel() {...}

@Override
public void showAllFilterLabel() {...}

@Override
public void showAddTask() {...}

@Override
public void showTaskDetailsUi(String taskId) {...}

@Override
public void showTaskMarkedComplete() {...}

@Override
public void showTaskMarkedActive() {...}

@Override
public void showCompletedTasksCleared() {...}

@Override
public void showLoadingTasksError() {...}

Соглашение MVO syncView() позволит нам удалить все эти методы. Это немного шокирует, если вы не привыкли к соглашению syncView(), но на самом деле все вышеперечисленное можно заменить:

@Override
public void syncView() {
  tasksView.setVisibility(taskListModel.hasVisibleTasks() ? View.VISIBLE :View.GONE);

  noTasksView.setVisibility(taskListModel.hasVisibleTasks() ? View.GONE :View.VISIBLE);
  noTaskMsg.setText(taskListModel.getCurrentFilter().noTasksStringResId);
  noTaskIcon.setImageDrawable(getResources().getDrawable(taskListModel.getCurrentFilter().noTasksDrawableResId));
  noTaskAddView.setVisibility(taskListModel.hasVisibleTasks() ? View.GONE : View.VISIBLE);
  filteringLabelView.setText(getResources().getString(taskListModel.getCurrentFilter().labelStringResId));
  swipeRefreshLayout.setRefreshing(taskFetcher.isBusy());

  listAdapter.notifyDataSetChangedAuto();
}

К тому времени, когда мы выполнили все просмотры, мы удалили много ненужного кода.

Сила соглашения syncView() подробно обсуждается здесь . Если вы знакомы с MVI, его назначение аналогично назначению функции render().

Анимированный список изменений

Вы заметили notifyDataSetChanged Auto() ? (вместо более обычного notifyDataSetChanged()) – это способ поддержки анимированных изменений списка, в данном случае он поддерживается Android DiffUtil, но есть еще одна более производительная версия, которую вы можете использовать для простого списка в памяти, продемонстрированного здесь . В любом случае, это простой вызов функции notifyDataSetChanged Auto() из вашего Syncview().

В этот момент вы, возможно, думаете, что передний должна быть какая-то огромная сложная библиотека для поддержки всего этого, на самом деле она крошечная (например, 500 строк крошечного кода). Большая часть энергии исходит от самой концепции MVO.

Опора вращения

Это не было бы МВО, если бы поддержка вращения и тестируемость не входила в стандартную комплектацию.

Тестирование

Некоторые из оригинальных тестов работают без каких-либо изменений, некоторые были изменены, а другие пришлось переписать. Тестирование приложения MVO немного больше сосредоточено на пакете функций и использует простые тесты JUnit. Но все еще существует множество тестов пользовательского интерфейса Android (для них мы используем Dagger 2 TestAppМодуль для моделирования моделей, управляющих уровнем представления, но чистое решение будет работать так же хорошо)

Вещи, которые мы на самом деле не улучшили…

Наш слой просмотра теперь выглядит намного тоньше, но нам все еще нужно немного шаблонов в классах действий для поддержки таких вещей, как панель действий, вид навигации, всплывающее меню и управление меню опций. К сожалению, именно так был разработан Android – существует предел тому, насколько мы можем избежать этих собственных классов и прилагаемой к ним котельной плиты.

Приложения для отдельных видов деятельности и Навигационный компонент Google / | может предлагать выход из этого, или может быть, нет . (Если вы новичок в разработке Android, вы быстро научитесь относиться к рекомендациям Google с осторожностью. Они просто пытаются разобраться во всем, как и все мы – иногда это помогает, иногда меньше.)

Самое приятное в MVO то, что он удаляет так много кода из слоя просмотра, что не так сложно полностью переписать этот слой просмотра (например, используя новую структуру навигации), и вам почти не придется касаться остальной части кода приложения.

Спасибо за чтение! Если вы думаете об использовании силы в своей команде, в документах fore большинство основ описано в легко усваиваемых примерах приложений, например адаптеры , сети или базы данных .

вот полный код для нашего форка MVO.

Оригинал: “https://dev.to/erdo/tutorial-android-architecture-blueprints-full-todo-app-mvo-edition-259o”