Статья навигация для android

Шаблон “координатор” часто используется в iOS-приложениях и был представлен Сорушем Ханлоу (Soroush Khanlou) с целью упростить навигацию по приложению. Есть мнение, что работа Соруша основана на подходе Application Controller, описанном в книге Patterns of Enterprise Application Architecture Мартином Фаулером (Martin Fowler).

Шаблон “координатор” призван решить следующие задачи:

  • борьба с Massive View Controller проблемой (о проблеме уже писали на хабре — прим. переводчика), которая зачастую проявляется с появлением God-Activity (активити с большим количеством обязанностей).
  • выделение логики навигации в отдельную сущность
  • переиспользование экранов приложения (активити/фрагментов) благодаря слабой связи с логикой навигации

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

Логика навигации описана в активити/фрагменте

Поскольку Android SDK требует Context для открытия новой активити (или FragmentManager для того, чтобы добавить фрагмент в активити), довольно часто логику навигации описывают непосредственно в активити/фрагменте. Даже примеры в документации к Android SDK используют этот подход.

В приведенном примере навигация тесно связана с активити. Удобно ли тестировать подобный код? Можно было бы возразить, что мы можем выделить навигацию в отдельную сущность и назвать ее, к примеру, Navigator, который может быть внедрен. Давайте посмотрим:

Получилось неплохо, но хочется большего.

Начну с вопроса: где бы вы расположили логику навигации при использовании MVVM/MVP?

В слое под презентером (назовем его бизнес-логикой)? Не очень хорошая идея, потому что скорее всего вы будете повторно использовать вашу бизнес-логику в других моделях представления или презентерах.

В слое представления? Вы действительно хотите перебрасывать события между представлением и презентером/моделью представления? Давайте посмотрим на пример:

Или если вы предпочитаете MVVM, можно использовать SingleLiveEvents или EventObserver

Или давайте поместим навигатор в модель представления вместо использования EventObserver’а как было показано в предыдущем примере

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

Координатор

Так где же нам разместить логику навигации? Бизнес-логика? Ранее мы уже рассмотрели этот вариант и пришли к выводу, что это не лучшее решение. Перебрасывание событий между представлением и моделью представления может сработать, но это не выглядит элегантным решением. Более того, представление все еще отвечает за логику навигации, хоть мы и вынесли ее в навигатор. Следуя методу исключения у нас остается вариант с размещением логики навигации в модели представления и этот вариант кажется перспективным. Но должна ли модель представления заботиться о навигации? Разве это не просто прослойка между представлением и моделью? Вот почему мы пришли к понятию координатора.

“Зачем нам еще один уровень абстракции?” — спросите вы. Стоит ли того усложнение системы? В маленьких проектах действительно может получиться абстракция ради абстракции, однако в сложных приложениях или в случае использования A/B тестов координатор может оказаться полезным. Допустим, пользователь может создать аккаунт и залогиниться. У нас уже появилась некоторая логика, где мы должны проверить залогинился ли пользователь и показать либо экран логина либо главный экран приложения. Координатор может помочь в приведенном примере. Обратите внимание, что координатор не помогает писать меньше кода, он помогает вынести код логики навигации из представления или модели представления.

Идея координатора предельно проста. Он знает только какой экран приложения надо открыть следующим. Например, когда пользователь нажимает на кнопку оплаты заказа, координатор получает соответствующее событие и знает, что далее необходимо открыть экран оплаты. В iOS координатор используется в качестве сервис локатора, для создания ViewController’ов и управления бэкстеком. Это достаточно много для координатора (помним про принцип единственной ответственности). В Android-приложениях система создает активити, у нас множество инструментов для внедрения зависимостей и есть бекстек для активити и фрагментов. А теперь давайте вернемся к оригинальной идее координатора: координатор просто знает какой экран будет следующим.

Читайте также:  Cyberpunk 2077 apk android

Пример: Новостное приложение с использованием координатора

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

Сценарий (Flow) содержит один или несколько экранов. В нашем примере новостной сценарий состоит из 2 экранов: “список статей” и “текст статьи”. Координатор получился предельно простым. При старте приложения мы вызываем NewsFlowCoordinator#start() чтобы показать список статей. Когда пользователь кликает по элементу списка вызывается метод NewsFlowCoordinator#readNewsArticle(id) и показывается экран с полным текстом статьи. Мы все еще работаем с навигатором (об этом мы поговорим немного позже), которому мы делегируем открытие экрана. У координатора отсутствует состояние, он не зависит от реализации бекстека и реализует только одну функцию: определяет куда пойти дальше.

Но как соединить координатор с нашей моделью представления? Мы последуем принципу инверсии зависимостей: мы будем передавать в модель представления лямбду, которая будет вызываться когда пользователь тапает по статье.

onNewsItemClicked: (Int) -> Unit — это лямбда, у которой один целочисленный аргумент и возвращает Unit. Обратите внимание, что лямбда может быть null, это позволит нам очистить ссылку для того чтобы избежать утечки памяти. Создатель модели представления (например, даггер) должен передать ссылку на метод координатора:

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

Приведенная реализация навигатора не идеальна, однако основная идея этого поста — введение в паттерн координатора. Стоит отметить, что поскольку навигатор и координатор не имеют состояния, то они могут быть объявлены в рамках приложения (например Singleton скоуп в даггере) и могут быть инстанциированы в Application#onCreate().

Давайте добавим авторизацию в наше приложение. Мы определим новый экран логина (LoginFragment + LoginViewModel, для простоты мы опустим восстановление пароля и регистрацию) и LoginFlowCoordinator. Почему бы не добавить новый функционал в NewsFlowCoordinator? Мы же не хотим получить God-Coordinator, который будет отвечать за всю навигацию в приложении? Также сценарий авторизации не относится к сценарию чтения новостей, верно?

Здесь мы видим, что на каждый UI-ивент есть соответствующая лямбда, однако нет лямбды для коллбека успешного логина. Это также деталь реализации и вы можете добавить соответствующую лямбду, однако у меня есть идея получше. Давайте добавим RootFlowCoordinator и подпишемся на изменения модели.

Таким образом, RootFlowCoordinator будет входной точкой нашей навигации вместо NewsFlowCoordinator. Давайте остановим наше внимание на RootFlowCoordinator. Если пользователь залогинен, то мы проверяем прошел ли он онбординг (об этом чуть позже) и начинаем сценарий новостей или онбординга. Обратите внимание, что LoginViewModel не принимает участия в этой логике. Опишем сценарий онбординга.

Онбординг запускается вызовом OnboardingFlowCoordinator#start(), который показывает WelcomeFragment (WelcomeViewModel). После клика по кнопке “next” вызывается метод OnboardingFlowCoordinator#welcomeShown(). Который показывает следующий экран PersonalInterestFragment + PersonalInterestViewModel, на котором пользователь выбирает категории интересных новостей. После выбора категорий пользователь тапает по кнопке “next” и вызывается метод OnboardingFlowCoordinator#onboardingCompleted(), который проксирует вызов RootFlowCoordinator#onboardingCompleted(), который запускает NewsFlowCoordinator.
Посмотрим как координатор может упростить работу с A/B тестами. Я добавлю экран с предложением совершить покупку в приложении и буду показывать его некоторым пользователям.

И снова мы не добавили никакой логики в представление или его модель. Решили добавить InAppPurchaseFragment в онбординг? Для этого понадобится изменить только координатор онбординга, поскольку фрагмент покупок и его viewmodel полностью независим от других фрагментов и мы свободно можем его повторно использовать в других сценариях. Координатор также поможет реализоваnь А/В тест, который сравнивает два сценария онбординга.

Полные исходники можно найти на гитхабе, а для ленивых я подготовил видеодемонстрацию

Полезный совет: используя котлин можно создать удобный dsl для описания координаторов в виде графа навигации.

Итоги:

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

Читайте также:  Андроид иконку нет места

В статье не упоминается использование координатора с шаблоном MVI. Возможно ли использовать координатор с этой архитектурой? Да, у меня есть отдельная статья.

Гугл недавно представил Navigation Controller как часть Android Jetpack. Как координатор соотносится с навигацией от гугла? Вы можете использовать новый Navigation Controller вместо навигатора в координаторах или непосредственно в навигаторе вместо ручного создания транзакций фрагментов.

А если я не хочу использовать фрагменты/активити и хочу написать свой бекстек для управления вьюхами — получится ли использовать координатор в моем случае? Я тоже задумался об этом и работаю над прототипом. Я напишу об этом в своем блоге. Мне кажется, что конечный автомат здорово упростит задачу.

Привязан ли координатор к single-activity-application подходу? Нет, вы можете использовать его в различных сценариях. Реализация перехода между экранами скрыта в навигаторе.

При описанном подходе получится огромный навигатор. Мы же вроде пытались уйти от God-Object’a? Мы не обязаны описывать навигатор в одном классе. Создайте несколько небольших поддерживаемых навигатора, например, отдельный навигатор для каждого пользовательского сценария.

Как работать с анимациями непрерывных переходов? Описывайте анимации переходов в навигаторе, тогда активити/фрагмент не будет ничего знать о предыдущем/следующем экране. Как навигатор узнает когда запускать анимацию? Допустим, мы хотим показать анимацию перехода между фрагментами А и Б. Мы можем подписаться на событие onFragmentViewCreated(v: View) с помощью FragmentLifecycleCallback и при наступлении этого события мы можем работать с анимациями так же, как мы это делали непосредственно в фрагменте: добавить OnPreDrawListener чтобы дождаться готовности и вызвать startPostponedEnterTransition(). Примерно так же можно реализовать анимированный переход между активити с помощью ActivityLifecycleCallbacks или между ViewGroup с помощью OnHierarchyChangeListener. Не забудьте потом отписаться от событий чтобы избежать утечек памяти.

Источник

Рейтинг лучших навигаторов без интернета для Android

Все современные Android смартфоны оснащены модулем GPS, который поддерживает связь со спутниками вне зависимости от наличия сотовой сети. Примерно по такому же принципу функционируют и оффлайн карты — они сохраняются в памяти телефона, поэтому доступ к ним можно получить абсолютно в любой момент.

Однако далеко не все навигационные приложения нормально выполняют свои функции в оффлайн режиме. Мы изучили тему и составили топ из 7 лучших навигаторов без интернета на Андроид. Большинство программ в списке бесплатные, так что вам будет из чего выбрать.

№7 – Sygic

Скачать: Google Play

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

Программа может работать как в вертикальном, так и горизонтальном режиме, поэтому она хорошо выглядит на планшетах. Карты детализированные, с полной информацией о достопримечательностях, отелях, различных инфраструктурных объектах и текущем трафике на дорогах. Sygic распространяется платно, цена рассчитывается в соответствии с количеством приобретаемых оффлайн карт – можно купить весь мир или только нужные регионы. Платеж разовый, все последующие обновления будут бесплатными, а для сомневающихся есть 7-дневный пробный период, позволяющий ознакомится со всеми возможностями навигатора.

№6 – MapFactor

Скачать: Google Play

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

Уникальность MapFactor заключается в возможности забить в программу размеры вашего транспортного средства, его проходимость, максимальную скорость и тому подобные параметры. На их основе приложение подберет оптимальный маршрут движения с учетом особенностей вашей машины. Имеется приятное голосовое сопровождение, озвучивающее все маневры, навигация в 3D формате и возможность проложить маршрут от двери до двери. Без подключения к интернету MapFactor функционирует стабильно и можете быть уверены – этот софт вас не подведет.

№5 – Navitel

Скачать: Google Play

Выбирая, какой офлайн навигатор для Андроид лучший, мы не могли игнорировать Navitel. Этот софт наверняка известен водителям, ведь навителовские карты используются многими производителями в штатных навигационных системах автомобилей. Приложение платное, на тестирование дается 7-дней, после чего придется разово купить карту нужного региона – цены вполне адекватные.

Читайте также:  Android create aar library

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

№4 – Яндекс.Навигатор

Скачать: Google Play

Еще один достойный русский навигатор без интернета – Яндекс.Навигатор. И хоть нормально работать с оффлайн картами он начал относительно недавно, у этого приложения есть ряд неоспоримых преимуществ относительно конкурентов. В отличие от Google.Maps, он умеет полноценно строить маршруты без сети, а у узкоспециализированных навигаторов вроде Навител и Sygic приложение Яндекса выигрывает тем, что офлайн карты здесь бесплатные.

Карты можно скачивать через настройки приложения, но их список ограничен Россией и странами СНГ, большая часть Европы остается недоступной. Навигатор ориентирован на автомобилистов, он поддерживает удобное голосовое управление с подсказками, и не мешает лишней информацией, которая важнее пешеходам. Если вам нужно подробное расписание работы заведений или поиск по достопримечательностям, качайте Яндекс.Карты – функция навигации в них встроена по умолчанию.

№3 – OsmAnd

Скачать: Google Play

OsmAnd является отличной альтернативой более популярным навигаторам. Разработчики сделали упор на высокую детализацию карт, поэтому он лучше подойдет для пешеходов, велосипедистов и туристов. К примеру, в приложении нет востребованной водителями навигации в режиме 3D. Зато на картах отлично проработаны мелкие населенные пункты, показаны маленькие тропинки, вплоть до мест для стоянок в лесах, и есть масса настроек отображения различных магазинов, памятников, остановок и тому подобных объектов.

Приложением можно пользоваться бесплатно. В Free-версии доступно скачивание 7 карт на выбор, чего с головой хватит рядовому юзеру. Платная версия без ограничений с картами всего мира доступна за разовый платеж в 999 рублей, и свою цену она сполна оправдывает. Кстати, в платной версии Османда есть уникальная фишка – возможность просматривать описания достопримечательностей из Википедии без интернета.

№2 – 2ГИС

Скачать: Google Play

Вряд ли программа нуждается в представлении. 2ГИС — удобный и, что самое главное, бесплатный справочник и навигатор на русском языке. Карты здесь представлены в 2D и 3D форматах, маршрут строится в оффлайне, так что приложение будет одинаково полезно как для водителей, так и для пешеходов.

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

№1 – MAPS.ME

Скачать: Google Play

Лучшие карты на телефон без интернета, по мнению многих пользователей, предлагает MAPS.ME. В этом приложении они максимально информативные. Даже в глубинке сервис показываем почти все, от новостроек до мелких тропинок, которых не видят конкуренты. Отображаются даже стихийные свалки! Такое возможно благодаря тому, что в обновлении карт участвуют миллионы пользователей MAPS.ME, которые ежедневно вносят в них актуальную информацию.

Программа имеет удобный современный интерфейс и одинаково хорошо подходит для любых способов перемещения. Практически всегда прокладываются оптимальные маршруты, вас не заведут в непроходимые дебри и не попросят развернуться через двойную сплошную. Карты MAPS.ME занимают в 2-3 раза меньше памяти, чем у конкурентов, имеют отлично работающий поиск по достопримечательностям и поддерживают возможность сохранения нужных мест. Все функции приложения полностью бесплатны, именно поэтому MAPS.ME стал топ-1 нашего рейтинга.

Подписывайтесь на наш Яндекс.Дзен, чтобы не пропустить крутые статьи

Telegram-канал с лучшими скидками и оперативным обновлением новостей

Geekville во «Вконтакте» — наша группа со всем актуальным контентом

Источник

Оцените статью