在 Jetpack Compose 中检索导航图作用域的视图模型中的参数

huangapple go评论59阅读模式
英文:

Retrieve parameters in navigation graph scoped viewmodel in Jetpack Compose

问题

与这个问题非常相似,但有一点不同:

https://stackoverflow.com/questions/64955859/scoping-states-in-jetpack-compose

我在导航图中有一个作用域化的 viewModel。我可以检索到它,但我找不到一种优雅的方法来检索参数...

NavHost(navController, ...) {
    ...
    composable(routeWithParameter) {
       // (A):在这里,我需要来自路由的 'args' 参数。
       // 我目前的解决方案是再次添加参数:
       val args = it.arguments?.getString("argumentKey") // 从路由中检索 'args'

       val state = it.getRememberedParent(navController) // 获取父级
       
       state.arguments?.putString("argumentKey", args ) // 再次在父级状态中添加 'args'
       
       val viewModel = hiltViewModel<TViewModel>(state)
       Log.d("MISC", "id =${System.identityHashCode(viewModel)}") // 与 (B) 相同的实例
       ...
    }
    composable(route) {
       // (B):      
       val viewModel = hiltViewModel<TViewModel>(it.getRememberedParent(navController))
       Log.d("MISC", "id =${System.identityHashCode(viewModel)}") // 与 (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<TViewModel>() 来构建 viewModel (A),因为这会导致为 (B) 创建另一个实例...

我没有在文档中找到任何窍门(https://developer.android.com/jetpack/compose/libraries#hilt)

=> 如何在 (A) 中检索路由参数而不重新插入它们?

OR

=> 如何在 (A) 中查找父级而不使用 getBackStackEntry(并且使用初始路由参数)来获取相同的作用域化实例?

英文:

Very similar to this issue but with a slight difference:
https://stackoverflow.com/questions/64955859/scoping-states-in-jetpack-compose

I have a scoped viewModel in a navigation graph. I can retrieve it but I do not find an elegant way of retrieving parameters ...

NavHost(navController, ...) {
    ...
    composable(routeWithParameter) {
       // (A): here, I need an &#39;args&#39; parameter from route. 
       // My current solution is to &#39;add again&#39; the parameter:
       val args = it.arguments?.getString(&quot;argumentKey&quot;) // retrieve &#39;args&#39; from route

       val state = it.getRememberedParent(navController) // get parent
       
       state.arguments?.putString(&quot;argumentKey&quot;, args ) // add again the &#39;args&#39; in parent state
       
       val viewModel = hiltViewModel&lt;TViewModel&gt;(state)
       Log.d(&quot;MISC&quot;, &quot;id =${System.identityHashCode(viewModel)}&quot;) // same instance as (B)
       ...
    }
    composable(route) {
       // (B):      
       val viewModel = hiltViewModel&lt;TViewModel&gt;(it.getRememberedParent(navController))
       Log.d(&quot;MISC&quot;, &quot;id =${System.identityHashCode(viewModel)}&quot;) //same instance as (A)
       ...
    }
    ...
}


@Composable
fun NavBackStackEntry.getRememberedParent(navController: NavHostController): NavBackStackEntry {
    val parentId = this.destination.parent!!.id
    return remember(this) { navController.getBackStackEntry(parentId) }
}

In the view model, parameters are retrieved using SavedStateHandle like this:


@HiltViewModel
class EditFarmViewModel @Inject constructor(
    state: SavedStateHandle,
) : ViewModel() {

 private val _args = checkNotNull(state.get&lt;String&gt;(&quot;argumentKey&quot;))

In order to get the same viewModel instance in (A) and (B), I cannot build viewModel (A) by simply using hiltViewModel<TViewModel>() without state as it leads to another instance beeing created for (B)...

I haven't found any trick in the doc (https://developer.android.com/jetpack/compose/libraries#hilt)

=> How to retrieve route parameters for (A) without re-inserting them?

OR

=> How to get the same scoped instance without using the getBackStackEntry to find parent in (A) (and so, use the initial route parameters)?

答案1

得分: 0

事实上,错误是我必须创建一个嵌套的图形来访问共享范围的视图模型可组合,并将导航参数传递给嵌套图形的根。

像这样:

NavHost(navController, ...) {
     // => 这里是嵌套导航图,是唯一带有参数的导航图
     navigation(route = routeWithParameters, startDestination = nestedrouteA
     ){
          composable(nestedrouteA) {
            val state = it.getRememberedParent(navController) // 获取父级
            val viewModel = hiltViewModel<TViewModel>(state)
            Log.d("MISC", "id =${System.identityHashCode(viewModel)}") // 与(B)相同的实例
            ...
         }
         composable(nestedrouteB) {
            // (B):      
            val viewModel = hiltViewModel<TViewModel>(it.getRememberedParent(navController))
            Log.d("MISC", "id =${System.identityHashCode(viewModel)}") // 与(A)相同的实例
            ...
         }
     }
     ...
}
英文:

In fact, the error was I had to create a nested graph to access shared scope viewmodel composable and give the navigation parameter to the nested graph root.

like this:

NavHost(navController, ...) {
     // =&gt; 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&lt;TViewModel&gt;(state)
            Log.d(&quot;MISC&quot;, &quot;id =${System.identityHashCode(viewModel)}&quot;) // same instance as (B)
            ...
         }
         composable(nestedrouteB) {
            // (B):      
            val viewModel = hiltViewModel&lt;TViewModel&gt;(it.getRememberedParent(navController))
            Log.d(&quot;MISC&quot;, &quot;id =${System.identityHashCode(viewModel)}&quot;) //same instance as (A)
            ...
         }
     }
     ...
}

huangapple
  • 本文由 发表于 2023年6月12日 06:50:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76452812.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定