[Разработка под Android] Пример модульного андроид приложения с помощью Navigation component и Koin (DI)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Разработчик, привет!В этом статье я хочу поделиться примером модульного андроид приложения с помощью NavComponent (JetPack) и Koin (DI).У нас в компании есть много разных андроид проектов, которые должны использовать фичи (Feature) друг друга - это некая экосистема. Чтобы этого добиться нам необходимо разрабатывать эти фичи максимально независимыми и гибкими.Требования к фичам можно сформулировать так:
- Фича должна иметь возможность подменить логику и UI независимо друг от друга.
- Для вызова фичи должно быть достаточно знать её интерфейс (метку) и необходимые параметры входа/выхода.
- Сама фича должна скрывать свою реализацию от других фич.
- Поддержка feature on-off из коробки.
Для меня feature - это логически объединенная система компонентов, которая выполняет некоторую функцию в приложении. Например, авторизация, покупка. Фича содержит свой UI граф (цепочку фрагментов), который должен храниться в backStack навигации, а после выхода из фичи, возвращать пользователя в точку вызова фичи.Условная схема приложения из двух фич:
На схеме приложение, в котором есть MainFragment (M) и две фичи (А и В). Из М можно перейти в фичи А и В. А из фичи В мы можем попасть в фичу А. Причем, после завершения фичи А мы должны вернуться в точку вызова: если мы попали в фичу А из M, то возвращаемся в М, а если вызывали фичу А из В, то в В. При этом стек навигации должен сохраняться. А1, А2, B1, B2 - фрагменты фич.Каждая фича состоит из трех физических модулей андроид проекта: API, BL, UI.
На рисунке стрелка указывает направление зависимости. A -> B - модуль А зависит от В.
- API модуль содержит интерфейсы и модели данных фичи, с которыми могут работать все другие модули. Lint правило: На API модуль могут ссылаться любые другие модули.
- BL модуль содержит бизнес-логику фичи. Модуль реализует API фичи. Модуль содержит internal классы - закрыт для других модулей, кроме DI компонента, которые подключается в приложение. Lint правило: На BL модуль может ссылаться только APP модуль.
- UI модуль содержит интерфейс фичи. Модуль содержит internal классы - закрыт для других модулей, кроме DI компонента, которые подключается в приложение и NavGraph, который подключается в граф приложения как nested graph. Lint правило: На UI модуль может ссылаться только APP модуль.
А приложение строится следующим образом:
- Мы создаем наши фичи модули
- Создаем модуль приложения (app)
- В app модуле собираем наш паззл компонентов из DI модулей
startKoin {
modules(
listOf(
AppKoinModule.create(),
FeatureAImplKoinModule.create(),
FeatureAUiKoinModule.create(),
FeatureBImplKoinModule.create(),
FeatureBUiKoinModule.create()
)
)
}
Чтобы изменить логику фичи, вам нужно реализовать дополнительный модуль, подключить к app и заменить всего лишь одну строчку в DI, и эта логика сразу распространится по всему приложению, не важно кто и где вызывает фичу. C UI модулем есть нюанс - это граф, его нужно будет добавить в root граф app модуля.
- Добавляем графы наших фич в root граф нашего приложения (app). Пока только статическое формирование графа, работаю над динамической, там немало проблем.
- Вызов фичи выглядит следующим образом:
appNavigator.navigateTo(FeatureADestination::class.java)
Вот как выглядит интерфейс (по сути это просто метка)
interface FeatureADestination : ModuleNavInfo
А интерфейс ModuleNavInfo содержит уже более конкретную информацию, как фичу нужно вызывать. Реализация FeatureADestination спрятана в UI модуле.
interface ModuleNavInfo {
fun getNavigationStartPointResId(): Int
fun isFeatureAvailable(): Boolean
}
Также в приложении есть navigator, который достает нужные фичи по их интерфейсам и выполняет переход. Реализация навигатора достаточно простая, вам нужно лишь вытащить зарегистрированную в DI реализацию ModuleNavInfo:
class KoinAppNavigator : AppNavigator {
private val navigationDestinationInternal = MutableLiveEvent<EventArgs<ModuleNavInfo>>()
override val navigationDestination =
navigationDestinationInternal as LiveData<EventArgs<ModuleNavInfo>>
private val navigationIntDestinationInternal = MutableLiveEvent<EventArgs<Int>>()
override val navigationResDestination: LiveData<EventArgs<Int>>
get() = navigationIntDestinationInternal
override fun <T : ModuleNavInfo> navigateTo(
moduleNavInfo: Class<T>
) {
val destination = KoinJavaComponent.get(moduleNavInfo) as ModuleNavInfo
navigationDestinationInternal.postValue(EventArgs(destination))
}
override fun navigateTo(destination: Int) {
navigationIntDestinationInternal.postValue(EventArgs(destination))
}
override fun <T : ModuleNavInfo> resolveModule(moduleNavInfo: Class<T>): ModuleNavInfo? {
return try {
KoinJavaComponent.get(moduleNavInfo)
} catch (e: Exception) {
null
}
}
override fun <T : ModuleNavInfo> isCanNavigateTo(moduleNavInfo: Class<T>): Boolean {
return resolveModule(moduleNavInfo) != null
}
}
ModuleNavInfo и AppNavigator можно расширить, здесь я показал самый простой пример. Например, вам точно понадобится передавать параметры и возвращать результат. Сделать это тоже можно через ModuleNavInfo. Например, для возврата результата фичи, можно добавить StateFlow и подписываться на него. Все получается лаконично и в одном месте. Также можно настроить взаимодействие с помощью внутренних сервисов, которые можно спрятать от внешнего мира в BL модулях.Код примера доступен на гитхаб.Спасибо за внимание!
===========
Источник:
habr.com
===========
Похожие новости:
- [Программирование, Разработка мобильных приложений, Разработка под Android] Google I/O: что нового представили Android-разработчикам (перевод)
- [Разработка под Android, Kotlin, Искусственный интеллект, Голосовые интерфейсы] На продуктах Just AI будут обучать разговорному искусственному интеллекту
- [Java, C++, Разработка под Android, C] Производительность Android Runtime vs NDK
- [Разработка под Android] Google Play сократит названия приложений с 50 до 30 символов
- [Разработка мобильных приложений, Разработка под Android] Как мы интегрировали Huawei Mobile Services в два этапа
- [Разработка под iOS, Разработка мобильных приложений, Разработка под Android] Сервис для UX-тестирования мобильных приложений за 45 часов: результаты онлайн-хакатона с Oprosso
- [JavaScript, Разработка мобильных приложений, Разработка под Android, IT-компании] Google удалила IDE DroidScript из магазина Google Play якобы из-за зловреда и обвинила разработчиков в мошенничестве
- [Платежные системы, Разработка мобильных приложений, Разработка под Android, Flutter] История разработки SDK для приема платежей в мобильном приложении на Flutter
- [Разработка мобильных приложений, Разработка под Android] Фоновая работа в Android: обзор возможностей WorkManager
- [Разработка мобильных приложений, Разработка под Android] Навигация в многомодульном приложении на Jetpack без магии и DI
Теги для поиска: #_razrabotka_pod_android (Разработка под Android), #_modularization, #_navigation, #_razrabotka_pod_android (
Разработка под Android
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 16:07
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Разработчик, привет!В этом статье я хочу поделиться примером модульного андроид приложения с помощью NavComponent (JetPack) и Koin (DI).У нас в компании есть много разных андроид проектов, которые должны использовать фичи (Feature) друг друга - это некая экосистема. Чтобы этого добиться нам необходимо разрабатывать эти фичи максимально независимыми и гибкими.Требования к фичам можно сформулировать так:
На схеме приложение, в котором есть MainFragment (M) и две фичи (А и В). Из М можно перейти в фичи А и В. А из фичи В мы можем попасть в фичу А. Причем, после завершения фичи А мы должны вернуться в точку вызова: если мы попали в фичу А из M, то возвращаемся в М, а если вызывали фичу А из В, то в В. При этом стек навигации должен сохраняться. А1, А2, B1, B2 - фрагменты фич.Каждая фича состоит из трех физических модулей андроид проекта: API, BL, UI. На рисунке стрелка указывает направление зависимости. A -> B - модуль А зависит от В.
startKoin {
modules( listOf( AppKoinModule.create(), FeatureAImplKoinModule.create(), FeatureAUiKoinModule.create(), FeatureBImplKoinModule.create(), FeatureBUiKoinModule.create() ) ) }
appNavigator.navigateTo(FeatureADestination::class.java)
interface FeatureADestination : ModuleNavInfo
interface ModuleNavInfo {
fun getNavigationStartPointResId(): Int fun isFeatureAvailable(): Boolean } class KoinAppNavigator : AppNavigator {
private val navigationDestinationInternal = MutableLiveEvent<EventArgs<ModuleNavInfo>>() override val navigationDestination = navigationDestinationInternal as LiveData<EventArgs<ModuleNavInfo>> private val navigationIntDestinationInternal = MutableLiveEvent<EventArgs<Int>>() override val navigationResDestination: LiveData<EventArgs<Int>> get() = navigationIntDestinationInternal override fun <T : ModuleNavInfo> navigateTo( moduleNavInfo: Class<T> ) { val destination = KoinJavaComponent.get(moduleNavInfo) as ModuleNavInfo navigationDestinationInternal.postValue(EventArgs(destination)) } override fun navigateTo(destination: Int) { navigationIntDestinationInternal.postValue(EventArgs(destination)) } override fun <T : ModuleNavInfo> resolveModule(moduleNavInfo: Class<T>): ModuleNavInfo? { return try { KoinJavaComponent.get(moduleNavInfo) } catch (e: Exception) { null } } override fun <T : ModuleNavInfo> isCanNavigateTo(moduleNavInfo: Class<T>): Boolean { return resolveModule(moduleNavInfo) != null } } =========== Источник: habr.com =========== Похожие новости:
Разработка под Android ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 16:07
Часовой пояс: UTC + 5