与此问题非常相似,但略有不同: 确定 Jetpack Compose 中的状态范围
我在导航图中有一个作用域视图模型。我可以检索它,但我找不到检索参数的优雅方法......
NavHost(navController, ...) {
...
composable(routeWithParameter) {
// (A): here, I need an 'args' parameter from route.
// My current solution is to 'add again' the parameter:
val args = it.arguments?.getString("argumentKey") // retrieve 'args' from route
val state = it.getRememberedParent(navController) // get parent
state.arguments?.putString("argumentKey", args ) // add again the 'args' in parent state
val viewModel = hiltViewModel<TViewModel>(state)
Log.d("MISC", "id =${System.identityHashCode(viewModel)}") // same instance as (B)
...
}
composable(route) {
// (B):
val viewModel = hiltViewModel<TViewModel>(it.getRememberedParent(navController))
Log.d("MISC", "id =${System.identityHashCode(viewModel)}") //same instance as (A)
...
}
...
}
@Composable
fun NavBackStackEntry.getRememberedParent(navController: NavHostController): NavBackStackEntry {
val parentId = this.destination.parent!!.id
return remember(this) { navController.getBackStackEntry(parentId) }
}
在视图模型中,使用 SavedStateHandle 检索参数,如下所示:
@HiltViewModel
class EditFarmViewModel @Inject constructor(
state: SavedStateHandle,
) : ViewModel() {
private val _args = checkNotNull(state.get<String>("argumentKey"))
为了在 (A) 和 (B) 中获得相同的 viewModel 实例,我无法通过简单地使用无状态的 hiltViewModel() 来构建 viewModel (A),因为这会导致为 (B) 创建另一个实例...
我在文档中没有发现任何技巧(https://developer.android.com/jetpack/compose/libraries#hilt)
=> 如何检索 (A) 的路由参数而不重新插入它们?
或
=> 如何在不使用 getBackStackEntry 在 (A) 中查找父级的情况下获取相同作用域的实例(因此,使用初始路由参数)?
事实上,错误是我必须创建一个嵌套图来访问共享范围视图模型可组合项并将导航参数提供给嵌套图根。
像这样:
NavHost(navController, ...) {
// => NESTED Navigation graph HERE that is the only one with arguments
navigation(route = routeWithParameters, startDestination = nestedrouteA
){
composable(nestedrouteA) {
val state = it.getRememberedParent(navController) // get parent
val viewModel = hiltViewModel<TViewModel>(state)
Log.d("MISC", "id =${System.identityHashCode(viewModel)}") // same instance as (B)
...
}
composable(nestedrouteB) {
// (B):
val viewModel = hiltViewModel<TViewModel>(it.getRememberedParent(navController))
Log.d("MISC", "id =${System.identityHashCode(viewModel)}") //same instance as (A)
...
}
}
...
}
对于 SharedViewModel,您可以检索嵌套 NavGraph 中父路由范围内的共享 ViewModel 的实例。
使用
parentEntry = remember(backStackEntry){navController.getBackStackEntry()}
-> 请参阅此链接。
这是手动输入的代码示例,可能有语法错误:
路线
// Home Route
@Serializable
data object HomeScreenObj
// Route for nested graph
@Serializable
data class NestedScreens(val id: String? = null)
// Routes inside nested graph
@Serializable
data class ScreenOneObj
@Serializable
data object ScreenTwoObj
下一步 封装 将导航代码保存在单个文件中。
NavGraph Builder 扩展功能
//Extension Function to encapsulate Nav Code
fun NavGraphBuilder.appDestinations(navController: NavController) {
composable<HomeScreenObject> {
HomeScreen(
onClickItem = { navController.navigate(NestedSettingsScreens(id = itemId)) }
)
}
//Nested Graph
navigation<NestedScreens>(startDestination = ScreenOneObj()) {
composable<ScreenOneObj> { backStackEntry ->
val parentEntry = remember(backStackEntry) {
navController.getBackStackEntry<NestedScreens>()
}
val viewModel: SharedViewModel = hiltViewModel(parentEntry)
ScreenOne(viewModel = viewModel)
}
composable<ScreenTwoObj> { backStackEntry ->
val parentEntry = remember(backStackEntry) {
navController.getBackStackEntry<NestedScreens>()
}
val viewModel: SharedViewModel = hiltViewModel(parentEntry)
ScreenTwo(viewModel = viewModel)
}
}
}