android - 如何使用共享的 ViewModel,并避免每次使用 Navigation Component 重复使用相同的实例

标签 android dagger android-viewmodel android-jetpack-navigation android-navigation-graph

我的应用包含一个 Activity多个Fragments ,遵循“单一 Activity 应用程序模型”,以便我可以使用 Navigation Component 正确实现导航在 Android 中 jetpack .

我的大部分屏幕 ( Fragments ) 都是独立的,不相互依赖,因此它们使用自己的 ViewModel

一些功能需要导航涉及多个 Fragment .由于这些功能在它们之间共享数据,这些数据通过 Fragments 来回传递,我使用共享 ViewModel(由 Google 推荐)。 我需要使用共享的相同实例 ViewModel在所有相关的Fragments ,因为我需要 Fragments共享共享的状态ViewModel .

要使用 ViewModel 的同一个实例在这些相关的Fragments ,我需要创建 ViewModel使用父级 Activity (不是 Fragment )在获取 ViewModel 时来自 ViewModelProviders :

val viewModel = ViewModelProviders.of(
            parentActivity, factory.create()
        ).get(SharedViewModel::class.java)

但是,这会产生一个问题: 当连续导航到第一个 Fragment 时这需要共享 ViewModel , ViewModelProviders.of()将返回 ViewModel 的相同实例和以前一样:ViewModel正在 Fragments 之间共享,但也在对这样实现的功能的不同导航之间。

我明白为什么会发生这种情况(Android 将 ViewModel 存储在 map 中,在使用 ViewModel 请求 ViewModelProviders.of() 时使用它),但我不知道我应该如何实现正确地“共享 ViewModel 模式”。

我看到的唯一解决方法是:

  • 创建一个不同的 Activity对于使用 Fragment 的功能与共享 ViewModel
  • 使用嵌套 Fragments , 并使用共同父级 Fragment对于使用 Fragment 的功能与共享 ViewModel

有了这两个选项,我就可以创建一个 ViewModel将在 Fragments 之间共享干预该功能,每次导航到该功能时都会有所不同。

我在这里看到的问题是,这似乎与 Navigation Component 的基本原理背道而驰。和单例 Activity应用程序。 以这种方式实现的每个功能都需要具有不同的导航图,因为它们将使用不同的导航主机。这会阻止我使用 Navigation Component 的一些不错的功能。 .

实现我想要的东西的正确方法是什么? 我是否遗漏了什么,或者它就是这样吗?

之前Navigation Component我会使用不同的 ActivitiesFragments并使用 DaggerActivity 关联的范围/Fragment为了达成这个。但我不确定只用一个 Activity 实现它的最佳方式是什么`

最佳答案

我发现这可以从 2.1.0-alpha02

开始完成

来自: https://developer.android.com/jetpack/androidx/releases/navigation#2.1.0-alpha02

You can now create ViewModels that are scoped at a navigation graph level via the by navGraphViewModels() property delegate for Kotlin users or by using the getViewModelStore() API added to NavController. b/111614463

基本上:

  1. 在导航图编辑器中,创建一个嵌套图,并为其分配一个 id
  2. 在提供 ViewModel 时,不要从 Activity 中执行。相反,使用 FragmentnavGraphViewModels 扩展函数。

例子:

导航图中的嵌套图

<navigation
        android:id="@+id/feature_nested_graph"
        android:label="Feature"
        app:startDestination="@id/firstFragment">
        <argument
            android:name="item_id"
            app:argType="integer" />
        <fragment
            android:id="@+id/firstFragment"
            [....]
        </fragment>
        [....]
    </navigation>

为了将 ViewModel 范围限定为 feature_nested_graph 嵌套导航间隙:

        val viewModel: SharedViewModel
                by fragment.navGraphViewModels(R.id.feature_nested_graph)

或者,如果正在注入(inject) ViewModel 并且您正在为此使用自定义工厂:

        val viewModel: SharedViewModel
                by fragment.navGraphViewModels(R.id.feature_nested_graph) { factory2.create(assessmentId) }

关于android - 如何使用共享的 ViewModel,并避免每次使用 Navigation Component 重复使用相同的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59378823/

相关文章:

android - Dagger2 错误 : Module Must Be Set

android-livedata - ViewModel Livedata 观察者调用轮换

android - 在前台服务中实现 Room 时的 ViewModel

在屏幕旋转时重新创建 Android ViewModel

c# - 如何根据条件更改 ListView 中的 Textcoroul 或 TextCell 的背景颜色

java - Androidplot 方向传感器中的条形图旋转

android - 以编程方式在 Kotlin 中自定义字体

android - 如何使用 Retrofit 处理多个 API 端点?

android - 使用 gradle 构建时出现 java.lang.ClassCastException : com. sun.tools.javac.code.Symbol$VarSymbol

android - 跨 Gradle 模块使用 Dagger Multibinding