使用导航组件将视图模型范围限定为多个片段(不是活动)

mar*_*987 24 android android-fragments android-viewmodel android-jetpack android-jetpack-navigation

我正在使用导航组件,我希望在几个片段之间共享一个视图模型,但是当我离开片段时应该清除它们(因此没有将它们范围限定到活动中)我试图将一个活动放在多个片段中方法。我已经设法使用多个导航主机实现了这一点,并使用 getParentFragment 将片段范围限定到它,但这只会导致更多的问题不得不将片段包装在其他父片段中,失去后退按钮无缝工作和其他黑客来获得一些应该工作的东西很简单。有没有人有关于如何实现这一目标的好主意?我想知道我是否可以使用 getViewModelStore 的任何东西,鉴于下面的图像,我想将视图模型范围限定为 createCardFragment2 并在它之后的任何内容中使用它(addPredictions、editImageFragment 和其他我没有的)

顺便说一句,我不能只在 mainFragment 视图模型存储上调用 clear,因为这里还有其他不应清除的视图模型,我想我想要一种方法来告诉导航主机我知道的父片段应该是什么不是如果我从 mainFragment 或 cardPreviewFragment 导航,这将是一件事,或者一种使视图模型更新的方法

导航图

Ale*_*x H 12

是的,现在可以将视图模型范围从androidx.navigation:*:2.1.0-alpha02. 请参阅此处的发行说明和此处的 API 示例。您需要提供的只是R.id您的导航图。不过,我觉得使用起来有点烦人,因为通常视图模型是在onCreate.配置更改的情况)。

此外,如果您不希望自己mainFragment成为该范围的一部分,我建议将其取出并使用嵌套导航图

  • 这里有一些代码的详细答案:/sf/answers/4335080851/ (3认同)

Mik*_*Chu 12

这是 Alex H 接受的答案的具体示例。

在你的 build.gradle (app)

dependencies {
    def nav_version = "2.1.0"
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
}
Run Code Online (Sandbox Code Playgroud)

视图模型示例

class MyViewModel : ViewModel() { 
    val name: MutableLiveData<String> = MutableLiveData()
}
Run Code Online (Sandbox Code Playgroud)

在你的 FirstFlowFragment.kt 中定义

val myViewModel: MyViewModel by navGraphViewModels(R.id.your_nested_nav_id)
myViewModel.name.value = "Cool Name"
Run Code Online (Sandbox Code Playgroud)

在你的 SecondFlowFragment.kt 中定义

val myViewModel: MyViewModel by navGraphViewModels(R.id.your_nested_nav_id)
val name = myViewModel.name.value.orEmpty()
Log.d("tag", "welcome $name!")
Run Code Online (Sandbox Code Playgroud)

现在 ViewModel 的作用域在这个嵌套片段中,当嵌套导航也被销毁时,共享状态也将被销毁,无需手动重置它们。

  • 我觉得很奇怪,你的“ViewModel”是在“Fragment”中实现(扩展)的......当然,“viewmodel”的范围将是“fragment”:它们是同一个对象......我不知道如果我在你的解决方案中遗漏了一些东西...... (2认同)

mar*_*987 5

所以当我发布这个功能时,功能就在那里,但没有按预期工作,从那时起我现在一直使用这个,这个问题不断得到更多关注,所以我想我会发布一个最新的例子,

使用

//Navigation
implementation "androidx.navigation:navigation-fragment:2.2.0-rc04"
// Navigation UI
implementation "androidx.navigation:navigation-ui:2.2.0-rc04"
Run Code Online (Sandbox Code Playgroud)

我得到这样的视图模型店主

private ViewModelStoreOwner getStoreOwner() {

        NavController navController = Navigation
                .findNavController(requireActivity(), R.id.root_navigator_fragment);
        return navController.getViewModelStoreOwner(R.id.root_navigator);
}
Run Code Online (Sandbox Code Playgroud)

我使用一个活动多个片段实现,但是使用这个我可以有效地将我的视图模型绑定到范围片段,并且使用新的实时数据,您甚至可以限制它

第一个 id 来自导航图片段

<?xml version="1.0" encoding="utf-8"?>
  <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <fragment
      android:id="@+id/root_navigator_fragment"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:name="androidx.navigation.fragment.NavHostFragment"
      app:defaultNavHost="true"
      app:navGraph="@navigation/root_navigator"/>

  </FrameLayout>
Run Code Online (Sandbox Code Playgroud)

第二个来自导航图的 id

  <?xml version="1.0" encoding="utf-8"?>
  <navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root_navigator"
    app:startDestination="@id/mainNavFragment">
Run Code Online (Sandbox Code Playgroud)

然后你就可以像这样使用它

private void setUpSearchViewModel() {
    searchViewModel = new ViewModelProvider(getStoreOwner()).get(SearchViewModel.class);
}
Run Code Online (Sandbox Code Playgroud)