Comments 4
Благодарю за статью! По удивительному совпадению сейчас пишу на точно такую же тему, но в контексте рефакторинга нашего проекта. Очень понравился ваш подход к получению родительского NavBackStackEntry – даже не думал, что так можно, обязательно возьму на заметку. Мы у нас на проекте сделали немного вычурно – создаем composable с navHost`ом, где описываем дочерние экраны –порождает огромное кол-во контроллеров, но зато есть возможность описать родительский контекст в одном месте, а не в каждой функции:
@Composable
private fun SomeModuleGraph() {
val navController = rememberNavController()
ScopedContext(::SomeKoinComponent) { //contains some dependencies required for both screens
RootRouteWithNavHostInside(
navController = navController,
builder = {
composable("screen1") {
LinkedContext(::Screen1Component) { //contains some dependencies for screen1 only
Screen1Route()
}
}
composable("screen2") {
LinkedContext(::Screen2Component) { //contains some dependencies for screen2 only
Screen2Route()
}
}
}
)
}
}
Подскажите, пожалуйста, думали ли в сторону того, чтобы создавать скоупы, не привязывая их к вьюмоделям? Я на данный момент пришел к выводу, что это невозможно, так как при реконфигурации скоуп пересоздается, но может быть у вас уже есть наработки как этого можно добиться.
И второй вопрос касательно вашего подхода: как выполнять операции, которые должны совершаться единожды при создании родительского скоупа? У вас родительский скоуп берется 3 раза в 3 дочерних экранах, единственный вариант – это выполнять операцию в конструкторе, что не является хорошей затеей.
Подскажите, пожалуйста, думали ли в сторону того, чтобы создавать скоупы, не привязывая их к вьюмоделям?
Да, изначально пробовал делать без них. Уперся в то, что без ViewModel не получалось понять, в какой момент закрыть скоуп фичи.
И второй вопрос касательно вашего подхода: как выполнять операции, которые должны совершаться единожды при создании родительского скоупа?
Для такого я создаю ViewModel, в скоупе фичи и выполняю действие внутри нее
Мы у нас на проекте сделали немного вычурно – создаем composable с navHost`ом, где описываем дочерние экраны –порождает огромное кол-во контроллеров, но зато есть возможность описать родительский контекст в одном месте, а не в каждой функции
А вы уже обрабатывали кейс, когда нужно передавать параметры в объект, который живет в рамках скоупа фичи? Это отдельное приключение
Для такого я создаю ViewModel, в скоупе фичи и выполняю действие внутри нее
У вас есть 3 экрана под скоупом AuthGraph. нужно чтобы при попадании в AuthGraph (не важно, в какой экран) у вас отработал метод fetch() при старте. Можете, пожалуйста, написать небольшой пример, как вы сделаете вызов? Важно, чтобы вызов был один раз за все время жизни AuthGraph.
А вы уже обрабатывали кейс, когда нужно передавать параметры в объект, который живет в рамках скоупа фичи? Это отдельное приключение
Возможно не очень понял, но у нас нет проблем с передачей объектов. Объект создаваемый в скоупе, доступен всем дочерним скоупам. При закрытии скоупа мы его теряем, что логично. Если нужно пробросить условный id в целый граф, то мы передаем его в конструктор при инициализации FeatureKoinComponent, где под капотом оборачиваем его в репозиторий или подгружаем в коин с квалифаером
У вас есть 3 экрана под скоупом AuthGraph. нужно чтобы при попадании в AuthGraph (не важно, в какой экран) у вас отработал метод fetch() при старте. Можете, пожалуйста, написать небольшой пример, как вы сделаете вызов? Важно, чтобы вызов был один раз за все время жизни AuthGraph.
Например, создаю AuthFeatureViewModel
Скрытый текст
class AuthFeatureViewModel : ViewModel() {
init {
// do something
}
}
Помещаю ее в скоуп фичи
Скрытый текст
val authModule = module {
scope<Screen.AuthGraph> {
viewModelOf(::AuthFeatureViewModel)
}
}
Инициализирую AuthFeatureViewModel
Скрытый текст
@Composable
private fun Content() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = Screen.AuthGraph
) {
navigation<Screen.AuthGraph>(
startDestination = Screen.AuthGraph.EmailInput
) {
composable<Screen.AuthGraph.EmailInput> { navBackStackEntry ->
val parentNavBackStackEntry = rememberParentBackStackEntry(navController, navBackStackEntry)
ParentScopeProvider<Screen.AuthGraph>(parentNavBackStackEntry) {
koinViewModel<AuthFeatureViewModel>()
ComposeScreenScopeProvider<Screen.AuthGraph.EmailInput> {
/* omitted code */
}
}
}
// omitted code
}
}
}
AuthFeatureViewModel создается в скоупе фичи. Но есть минус с дублированием кода, потому что этот код
Скрытый текст
ParentScopeProvider<Screen.AuthGraph>(parentNavBackStackEntry) {
koinViewModel<AuthFeatureViewModel>()
// omitted code
}
Должен находиться в декларации каждого экрана, на который может быть совершен самый первый переход в рамках AuthGraph
Управление зависимостями: как работать с Koin scopes в Jetpack Compose Navigation