#android #android-jetpack-compose #jetpack-compose-navigation
Вопрос:
Однажды мне понадобилась библиотека аккомпаниаторов Google, реализованная в моем проекте создания Jetpack. Поскольку библиотека зависит от текущей стабильной версии Compose, мне пришлось обновить ее вместе с navigation-compose
библиотекой. Все сломалось.
Я использую BottomNavigation
в качестве навигации верхнего уровня и глубже ориентируюсь внутри вкладок, связанных с этим BottomNavigation
. Каждая вкладка имеет свою собственную NavHostController
, которую я хочу сохранить в a Bundle
, чтобы восстановить контроллер позже. Пример использования:
- Пользователь открывает вкладку 1
- Переход на другой экран с внутренней вкладки 1
- Переключается на вкладку 2
- Переключается обратно на вкладку 1. Экран, открытый на шаге 2, является текущим местом назначения вкладки 1
NavGraph
Код, приведенный в Предыдущем состоянии, работает по назначению.
До
Мои зависимости до миграции(составьте версию 1.0.0-alpha12):
// Compose
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling:$compose_version"
implementation "androidx.compose.material:material-icons-extended:$compose_version"
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
implementation "androidx.navigation:navigation-compose:1.0.0-alpha07"
В моем составном устройстве верхнего уровня, где BottomNavigation
это называется, у меня есть состояние:
val employeesNavState = rememberSaveable { mutableStateOf(Bundle()) }
Который я передаю на свою вкладку composable:
EmployeesTab(employeesNavState)
Это описывается следующей функцией:
@Composable
fun EmployeesTab(navState: MutableState<Bundle>) {
val navController = rememberNavController() // The navController responsible for navigation state
DisposableEffect(null) {
val callback = NavController.OnDestinationChangedListener { controller, _, _ ->
// The state is saved on each navigation event
navState.value = controller.saveState() ?: Bundle()
}
navController.addOnDestinationChangedListener(callback)
// The state is restored from the navState created by the callback
navController.restoreState(navState.value)
onDispose {
navController.removeOnDestinationChangedListener(callback)
// workaround for issue where back press is intercepted
// outside this tab, even after this Composable is disposed
navController.enableOnBackPressed(false)
}
}
NavHost(navController, startDestination = "employees") {
composable("employees") {
appBarViewModel.onNavigate(AppScreen.Employees, navController)
Employees(it.hiltViewModel(), navController)
}
composable("employee/{userId}") {
appBarViewModel.onNavigate(AppScreen.EmployeeDetails, navController)
Employee(it.hiltViewModel())
}
}
}
После
Мои зависимости после миграции(составьте версию 1.0.3):
// Compose
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling:$compose_version"
implementation "androidx.compose.material:material-icons-extended:$compose_version"
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
implementation "androidx.navigation:navigation-compose:2.4.0-alpha10"
implementation "com.google.accompanist:accompanist-flowlayout:0.19.0"
И каждый отдельный бит другого кода остается прежним. Каким-то образом это просто перестало работать. Я сделал некоторую отладку и убедился controller.saveState()
, что не возвращается null
. Обратный вызов выполняется в обеих версиях.
Единственное , что я обнаружил, что отличается, — это navigate()
функция NavController
, которая является функцией расширения navigation-compose:1.0.0-alpha07
и функцией-членом navigation-compose:2.4.0-alpha10
. Я называю это изнутри Employees
составного.
Вопрос
Что изменилось внутри API, что он перестал работать без каких-либо ошибок? Как мне изменить свой код, чтобы воспроизвести поведение «До»?
Комментарии:
1. Почему вы вообще используете несколько навигационных хостов? Вам не нужно ничего из этого, чтобы сохранить состояние каждой вкладки — это то
saveState
restoreState
, что делают для вас флаги и в примере интеграции нижней навигации .2. @ianhanniballake, я унаследовал этот проект от другого разработчика, и вот как он реализовал это поведение. Я последую примеру по предоставленной ссылке и опубликую обновление. Спасибо