Доступ к графической области ViewModel дочернего NavHostFragment с помощью navGraphViewModels
Я использую навигационный компонент Android Jetpack (2.2.0-alpha01).
Я хочу использовать дочерний NavHostFragment, вложенный в мой основной NavHostFragment, оснащенный собственным дочерним графом навигации. Пожалуйста, просмотрите следующее изображение для контекста:
Дочерний навигационный хост определяется следующим образом внутри фрагмента, который находится в передней части стека MainNavHost:
<fragment
android:id="@+id/childNavHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="false"
app:navGraph="@navigation/child_graph" />
Внутри фрагмента, который находится в передней части фрагмента хоста CHILD Nav, я пытаюсь получить область видимости, связанную с R.navigation.child_graph, используя следующий код:
private val childGraphScopedViewModel: ChildGraphScopedViewModel by navGraphViewModels(R.navigation.child_graph) {
viewModelFactory
}
При доступе к childGraphScopedViewModel я получаю сбой с сообщением об ошибке:
java.lang.IllegalArgumentException: No NavGraph with ID 2131689472 is on the NavController's back stack.
Я считаю ленивый вызов init by navGraphViewModel()
ищет navgraph внутри mainGraph.
Как я могу получить доступ к дочерней модели NavHostFragment в области ViewModel? Спасибо за уделенное время.
0 ответов
Это работает для меня без определения aby custom ViewModelProvider
(2.2.0):
private val viewModel: ChildGraphScopedViewModel by navGraphViewModels(R.id. child_graph)
Легкая ошибка - использовать R.navigation.child_graph
(плохо) вместо R.id.child_graph
(хороший)
Вы можете сделать это, предоставив viewModelStore дочернего элемента NavController
override fun onViewCreated(
view: View,
savedInstanceState: Bundle?
) {
super.onViewCreated(view, savedInstanceState)
val childHostFragment = childFragmentManager
.findFragmentById(R.id.childNavHostFragment) as NavHostFragment
val childNavController = childHostFragment.navController
val childViewModel: ChildGraphScopedViewModel = ViewModelProvider(
childNavController.getViewModelStoreOwner(R.navigation.child_graph)
).get(ChildGraphScopedViewModel::class.java)
}
Я написал расширение Kotlin, чтобы было проще
inline fun <reified T: ViewModel> NavController.viewModel(@NavigationRes navGraphId: Int): T {
val storeOwner = getViewModelStoreOwner(navGraphId)
return ViewModelProvider(storeOwner)[T::class.java]
}
Применение
val viewModel = findNavController().viewModel(R.navigation.nav)
По какой-то причине создание навигационного графа и использование include
вложить его в основной навигационный граф у меня не получалось. Наверное, это ошибка.
Вы можете выбрать все фрагменты, которые необходимо сгруппировать внутри навигационного графа, и right-click->move to nested graph->new graph
теперь это переместит выбранные фрагменты во вложенный граф внутри основного навигационного графа следующим образом:
<navigation app:startDestination="@id/homeFragment" ...>
<fragment android:id="@+id/homeFragment" .../>
<fragment android:id="@+id/productListFragment" .../>
<fragment android:id="@+id/productFragment" .../>
<fragment android:id="@+id/bargainFragment" .../>
<navigation
android:id="@+id/checkout_graph"
app:startDestination="@id/cartFragment">
<fragment android:id="@+id/orderSummaryFragment".../>
<fragment android:id="@+id/addressFragment" .../>
<fragment android:id="@+id/paymentFragment" .../>
<fragment android:id="@+id/cartFragment" .../>
</navigation>
</navigation>
Теперь внутри фрагментов при инициализации ViewModel сделайте это
val viewModel: CheckoutViewModel by navGraphViewModels(R.id.checkout_graph)
Если вам нужно передать фабрику модели просмотра (может быть, для внедрения модели просмотра), вы можете сделать это следующим образом:
val viewModel: CheckoutViewModel by navGraphViewModels(R.id.checkout_graph) { viewModelFactory }