Android 如何使用共享ViewModel,并避免每次使用导航组件时重复使用同一个ViewModel实例
我的应用程序由一个Android 如何使用共享ViewModel,并避免每次使用导航组件时重复使用同一个ViewModel实例,android,dagger,android-viewmodel,android-jetpack-navigation,android-navigation-graph,Android,Dagger,Android Viewmodel,Android Jetpack Navigation,Android Navigation Graph,我的应用程序由一个活动和多个片段组成,遵循“单一活动应用程序模型”,因此我可以使用Androidjetpack中的导航组件正确实现导航 我的大多数屏幕(Fragments)是独立的,彼此不依赖,因此它们使用自己的ViewModel 有些功能需要涉及多个片段的导航。由于这些功能在它们之间共享通过片段来回传递的数据,我使用共享视图模型(如谷歌推荐的)。 我需要在所有关联的片段中使用共享视图模型的相同实例,就像我需要片段共享视图模型的状态一样 要在这些关联的片段中使用视图模型的相同实例,我需要在从视图
活动
和多个片段组成,遵循“单一活动应用程序模型”,因此我可以使用Androidjetpack
中的导航组件
正确实现导航
我的大多数屏幕(Fragments
)是独立的,彼此不依赖,因此它们使用自己的ViewModel
有些功能需要涉及多个片段的导航。由于这些功能在它们之间共享通过片段来回传递的数据,我使用共享视图模型(如谷歌推荐的)。
我需要在所有关联的片段
中使用共享视图模型
的相同实例,就像我需要片段
共享视图模型
的状态一样
要在这些关联的片段
中使用视图模型
的相同实例,我需要在从视图模型提供程序
获取视图模型
时,使用父活动
(而不是片段
)创建视图模型
:
val viewModel = ViewModelProviders.of(
parentActivity, factory.create()
).get(SharedViewModel::class.java)
然而,这是可行的,它产生了一个问题:
当连续多次导航到需要共享的ViewModel
的第一个片段时,ViewModelProviders.of()
将返回与前面相同的ViewModel
实例:在片段之间共享ViewModel
,但也可以在不同的导航之间切换到这样实现的功能
我理解为什么会发生这种情况(Android将ViewModel存储在映射中,当使用ViewModelProviders.of()
请求ViewModel
时使用该映射),但我不知道如何正确实现“共享ViewModel模式”
我看到的唯一解决办法是:
- 为使用共享
视图模型的片段的功能创建不同的活动
- 使用嵌套的
片段
,对于将片段
与共享的视图模型一起使用的功能,使用公共父级片段
有了这两个选项,我将能够创建一个ViewModel
,它将在介入该功能的片段之间共享,并且每次导航到该功能时都会有所不同
我在这里看到的问题是,这似乎违背了导航组件
和单个活动
应用程序的基本原理。
以这种方式实现的每个功能都需要有不同的导航图,因为它们将使用不同的导航主机。这将阻止我使用导航组件的一些优秀功能
实现我想要的东西的正确方法是什么?
我是否遗漏了什么,或者是这样的吗
在导航组件之前
我将使用不同的活动
和片段
,并使用与活动
/片段
关联的匕首
范围来实现这一点。但是我不确定用一个活动来实现这一点的最佳方式是什么`您有一个共享的视图模型的相同实例,因为它属于活动
——这很清楚。我不清楚您的用例,但通常当我需要执行类似操作时,我只需从Fragment的onCreate
或或createview
传递一些标识符来通知ViewModel
。在您的情况下,它可能类似于:
viewModel.onNavigatedTo("fragment1")
通过这种方式,共享视图模型可以区分当前使用它的片段并相应地刷新状态。我发现可以从2.1.0-alpha02
发件人:
现在,您可以创建范围在导航图上的视图模型
通过Kotlin的by navGraphViewModels()属性委托的级别
用户或使用添加到NavController的getViewModelStore()API。
b/111614463
基本上:
在导航图形编辑器中,创建嵌套图形,并为其指定一个id
提供视图模型时,不要从活动中执行此操作。相反,使用
Fragment
的navGraphViewModels
扩展函数
例如:
导航图中的嵌套图
<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>
或者,如果您正在注入视图模型
,并且正在为此使用自定义工厂:
val viewModel: SharedViewModel
by fragment.navGraphViewModels(R.id.feature_nested_graph) { factory2.create(assessmentId) }
val viewModel: SharedViewModel
by fragment.navGraphViewModels(R.id.feature_nested_graph) { factory2.create(assessmentId) }