如何将视图模型范围限定为父片段?

mar*_*987 11 android viewmodel android-fragments android-architecture-navigation

所以我正在使用新的导航组件(具有一个活动原则)并使用共享视图模型在每个片段之间进行通信,但是,我有时需要清除视图模型但我找不到清除它的好地方。但是 tbh 我认为与其试图自己清除它,我真的应该允许框架为我做这件事,但这不是因为视图模型是共享的并限定于活动,但我认为我可以将它们限定为一个父片段,我画了一张图来说明我想要做什么。我的导航流程 所以当我从“Child 1 Child a”导航回来时,我只想清除 2 个视图模型,当前视图模型永远不会被清除,试图通过在片段中调用“this”来获取当前的视图模型,而 getParentFragment 在孩子中没有不行,谁能举个例子?

编辑

看起来我已经在做类似的事情,但在我的情况下它不起作用所以我将添加一些代码,这是我如何访问父片段中的第一个视图模型

model = ViewModelProviders.of(this).get(RequestViewModel.class);
Run Code Online (Sandbox Code Playgroud)

然后在子片段中,我正在这样做

requestViewModel = ViewModelProviders.of(getParentFragment()).get(RequestViewModel.class);
Run Code Online (Sandbox Code Playgroud)

但这并没有保留他们之间的数据,他们都附加了观察者

Alo*_*hra 26

在您的应用程序中使用Fragment-ktx libr,您可以在您的应用程序-> build.gradle 中获得如下所示的 viewModel

 implementation 'androidx.fragment:fragment-ktx:1.1.0'
Run Code Online (Sandbox Code Playgroud)

// 获取ParentFragment中的ViewModel作为

 private val viewModel: DemoViewModel by viewModels()
Run Code Online (Sandbox Code Playgroud)

//得到相同的实例 视图模型在ChildFragment作为

 private val viewModel: DemoViewModel by viewModels(
    ownerProducer = { requireParentFragment() }
)
Run Code Online (Sandbox Code Playgroud)

  • 目前存在一个错误,当将 hilt 绑定到导航组件时,您需要指定默认视图模型工厂,否则这将是事实上的方法 (2认同)

Ndr*_*iku 11

如果您使用导航组件(https://developer.android.com/guide/navigation),您需要通过以下方式获取 viewModel:

在您的应用程序 -> build.gradle 中实现fragment-ktx :

implementation 'androidx.fragment:fragment-ktx:1.2.5
Run Code Online (Sandbox Code Playgroud)

在父片段中:

private val viewModel by viewModels<ParentFragmentViewModel>()
Run Code Online (Sandbox Code Playgroud)

在子片段中

private val viewModel by viewModels<ParentFragmentViewModel>({requireGrandParentFragment()})
Run Code Online (Sandbox Code Playgroud)

requireGrandParentFragment ()是 Fragment 的自定义扩展:

fun Fragment.requireGrandParentFragment() = this.requireParentFragment().requireParentFragment()
Run Code Online (Sandbox Code Playgroud)

您需要向上两级才能访问parentFragment的viewModel的原因是因为导航组件上childFragment的第一个父级是NavHostFragment,而NavHostFragment的父级是viewModel所在的parentFragment 。

如果您不使用导航组件,您可以在 childFragment 中像这样访问它:

private val viewModel by viewModels<ParentFragmentViewModel>({requireParentFragment()})
Run Code Online (Sandbox Code Playgroud)


mar*_*987 8

好的,所以在父级中使用它

model = ViewModelProviders.of(this).get(RequestViewModel.class);
Run Code Online (Sandbox Code Playgroud)

这在孩子身上

requestViewModel = ViewModelProviders.of(getParentFragment()).get(RequestViewModel.class);
Run Code Online (Sandbox Code Playgroud)

给了我不同的哈希码但相同的 ID,这似乎是因为导航组件,如果我将它们都更改为 getParentFragment 那么它就可以工作,所以我认为该组件正在替换片段而不是在此处添加它们,非常感谢@WadeWilson和@JeelVankhede


Jee*_*ede 8

所以,按照@马丁的提议的解决方案,即使单/多片段添加导出子里面父片段,导航组件提供相同的片段经理到两个片段。

这意味着即使片段被添加为父子层次结构,它们也会共享来自导航组件的相同片段管理器(可能是这个库中的错误?) &因此ViewModels当使用getParentFragment()实例作为ViewModelProvider内部子片段时,由于这种困境而不会共享。


因此,共享的一种快速解决方案ViewModels是使用以下行获取父片段的父片段实例从片段管理器中获取父片段和子片段:

ViewModelProviders.of(getParentFragment()).get(SharedViewModel.class); // using this in both parent amd child fragment would do the trick !
Run Code Online (Sandbox Code Playgroud)


fre*_*yle 5

Google 现在让我们能够将 ViewModel 范围限定为导航图。如果您已经在使用导航组件,则可以使用它。(个人观点,如果您还没有使用导航组件,您应该转向导航组件,因为它非常容易使用。从一个尝试自己管理后堆栈的人那里获取它)

您可以选择需要在导航图中分组在一起的所有片段,然后right-click->move to nested graph->new graph

现在,这会将选定的片段移动到主导航图中的嵌套图,如下所示:

<navigation app:startDestination="@id/homeFragment" ...>
    <fragment android:id="@+id/homeFragment" .../>
    <fragment android:id="@+id/productListFragment" .../>
    <fragment android:id="@+id/productFragment" .../>
    <fragment android:id="@+id/bargainFragment" .../>
    
    <navigation 
        android:id="@+id/checkout_graph" 
        app:startDestination="@id/cartFragment">

        <fragment android:id="@+id/orderSummaryFragment".../>
        <fragment android:id="@+id/addressFragment" .../>
        <fragment android:id="@+id/paymentFragment" .../>
        <fragment android:id="@+id/cartFragment" .../>

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

现在,在初始化 ViewModel 时在片段内执行此操作

val viewModel: CheckoutViewModel by navGraphViewModels(R.id.checkout_graph)
Run Code Online (Sandbox Code Playgroud)

如果您需要传递视图模型工厂(可能用于注入视图模型),您可以这样做:

val viewModel: CheckoutViewModel by navGraphViewModels(R.id.checkout_graph) { viewModelFactory }
Run Code Online (Sandbox Code Playgroud)

确保它R.id.graph和不是R.navigation.graph

由于某种原因,创建导航图并将include其嵌套在主导航图中对我来说不起作用。可能这是一个错误。

来源:https ://medium.com/androiddevelopers/viewmodels-with-saved-state-jetpack-navigation-data-binding-and-coroutines-df476b78144e

谢谢,手动清除 Android ViewModel?为我指明了正确的方向。


归档时间:

查看次数:

12721 次

最近记录:

5 年,5 月 前