NavigationViewModel неожиданно очищается, когда экран извлекается из заднего стекаAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 NavigationViewModel неожиданно очищается, когда экран извлекается из заднего стека

Сообщение Anonymous »

Предположим, у меня есть два экрана:
  • Экран А.
  • Экран Б.
Когда я отправляю NavigationUiEvent.ShowScreenB в NavigationModel, NavigationModel передает это событие в SharedFlow.< /p>
Этот поток собирается с помощью CollectAsStateWithLifecycle в составной функции Navigator. Затем этот Navigator использует NavHostController для навигации.
Если я нажимаю кнопку «Назад», приложение отображает Экран B, и я вернемся к Экрану A.
Как ни странно, во время появления вызывается NavigationModel#onCleared. Я выбрал эту трассировку стека вручную:

Код: Выделить всё

com.myapp.presentation.viewmodels.NavigationViewModel.onCleared(NavigationViewModel.kt:59)
androidx.lifecycle.ViewModel.clear(ViewModel.java:202)
androidx.lifecycle.ViewModelStore.clear(ViewModelStore.kt:69)
androidx.navigation.NavControllerViewModel.clear(NavControllerViewModel.kt:33)
androidx.navigation.NavController$NavControllerNavigatorState.markTransitionComplete(NavController.kt:359)
androidx.navigation.compose.ComposeNavigator.onTransitionComplete(ComposeNavigator.kt:8androidx.navigation.compose.NavHostKt$NavHost$15.invokeSuspend(NavHost.kt:314)
Из-за этого область и поток NavigationViewModel отменяются и не принимают никаких новых событий NavigationUiEvent, поэтому я застрял на экране A .

Пожалуйста, взгляните на мой код ⤵️

Код: Выделить всё

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
Surface(modifier = Modifier.fillMaxSize()) {
Box(modifier = Modifier.fillMaxSize()) {
SetupAppNavigation()
}
}
}
}
}
}

@Composable
fun SetupAppNavigation() {
val navController = rememberNavController()

Navigator(navHostController = navController) // sits on top of the nav host

NavHost(
navController = navController,
startDestination = "screen_a",
) {
composable(route = "screen_a") {
ScreenARoute()
}

composable(route = "screen_b") {
ScreenBRoute()
}
}
}

@Composable
fun Navigator(
navHostController: NavHostController,
) {
val navigationViewModel: NavigationViewModel = koinViewModel()
val navDirection: NavigationUiEvent? by navigationViewModel.state.collectAsStateWithLifecycle(initialValue = null)

when (val nav = navDirection) {
is NavigationUiEvent.ScreenB -> navHostController.navigate(route = "screen_b")
null -> Unit // Nothing to do here
}
}

class NavigationViewModel internal constructor() : ViewModel(), NavigationUiEventHandler, KoinComponent {

private val module: Module by lazy {
module {
single { this@NavigationViewModel } bind NavigationUiEventHandler::class
}
}

private val events = MutableSharedFlow()

val state: SharedFlow = events
.onStart { getKoin().loadModules(listOf(module)) }
.onCompletion { getKoin().unloadModules(listOf(module)) }
.shareIn(
scope = viewModelScope,
started = SharingStarted.Eagerly,
)

override fun handleEvent(event: NavigationUiEvent) {
viewModelScope.launch {
events.emit(event)
}
}

override fun onCleared() {
super.onCleared()
println("DEBUG >> NavigationViewModel CLEARED so YEAH GOODBYE !")
}
}

# KOIN INJECTION #

val viewModelsModule = module {
viewModeOf(::NavigationViewModel)
viewModeOf(::ScreenAViewModel)
viewModeOf(::ScreenBViewModel)
}

class MyApp: Application() {
override fun onCreate() {
super.onCreate()

startKoin {
androidLogger()
androidContext(this@ MyApp)
modules(
listOf(
viewModelsModule,
...
)
)
}
}
}
Приложение печатает...

Код: Выделить всё

DEBUG >> NavigationViewModel CLEARED so YEAH GOODBYE !
... когда я возвращаюсь к экрану А.
Почему?
Честно говоря, я не знаю не понимаю, почему NavControllerViewModel (из трассировки стека) очищает мою NavigationViewModel даже если она явно не привязана к конкретному экрану как часть моего графа навигации.< /п>

Подробнее здесь: https://stackoverflow.com/questions/791 ... from-the-b
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»