model = ViewModelProviders.of(this).get(RequestViewModel.class);
然后在子片段中,我正在进行这个操作
requestViewModel = ViewModelProviders.of(getParentFragment()).get(RequestViewModel.class);
但它没有在它们之间保留数据,它们都连接了观察者
model = ViewModelProviders.of(this).get(RequestViewModel.class);
然后在子片段中,我正在进行这个操作
requestViewModel = ViewModelProviders.of(getParentFragment()).get(RequestViewModel.class);
但它没有在它们之间保留数据,它们都连接了观察者
在您的应用程序中使用Fragment-ktx库,您可以按如下方式获取viewModel 在您的应用程序-> build.gradle
implementation 'androidx.fragment:fragment-ktx:1.1.0'
// 获取ParentFragment中的ViewModel示例,代码如下:
private val viewModel: DemoViewModel by viewModels()
// 在 ChildFragment 中获取与 ViewModel 相同的实例
private val viewModel: DemoViewModel by viewModels(
ownerProducer = { requireParentFragment() }
)
好的,那么在父元素中使用它
model = ViewModelProviders.of(this).get(RequestViewModel.class);
而这是在孩子中
requestViewModel = ViewModelProviders.of(getParentFragment()).get(RequestViewModel.class);
给我的不同哈希码但相同的ID,看起来是由于导航组件,如果我将它们都更改为getParentFragment,则可以解决问题,因此我认为该组件在此处替换了片段而不是添加它们,特别感谢@WadeWilson和@JeelVankhede。
Unsafe call to observe with Fragment instance as LifecycleOwner from MyFragment.onViewCreated.
- Bagus Aji Santosoby viewModels
来惰性创建viewModels。为了在片段和它启动的底部SheetFragmentDialog之间共享相同的viewModel,我需要在片段和bottomSheetFragment中都使用by viewModels({ requireParentFragment() })
。 - dumbfingersimplementation 'androidx.fragment:fragment-ktx:1.2.5
在父 Fragment 中:
private val viewModel by viewModels<ParentFragmentViewModel>()
private val viewModel by viewModels<ParentFragmentViewModel>({requireGrandParentFragment()})
requireGrandParentFragment()是Fragment的自定义扩展:
fun Fragment.requireGrandParentFragment() = this.requireParentFragment().requireParentFragment()
你需要向上转两级才能访问父Fragment的viewModel,因为导航组件中子Fragment的第一个父级是NavHostFragment,而NavHostFragment的父级是包含viewModel的parentFragment。
如果您没有使用Navigation组件,则可以在子Fragment中像这样访问它:
private val viewModel by viewModels<ParentFragmentViewModel>({requireParentFragment()})
这意味着,即使片段被添加为父子层次结构,它们也会从导航组件共享相同的Fragment管理器(可能是该库中的错误?),因此,在使用getParentFragment()
实例为子片段中的ViewModelProvider
时,ViewModels
不会被共享。
因此,共享ViewModels
的一种快速解决方法是,通过以下行从片段管理器获取父片段的实例,对于父片段和子片段都是如此:
ViewModelProviders.of(getParentFragment()).get(SharedViewModel.class); // using this in both parent amd child fragment would do the trick !
getParentFragment()
不会返回 null。在这种情况下,该方法会抛出异常。 - Archie G. Quiñones现在,Google 已经使得我们能够将 ViewModel 的范围限定在导航图中。如果您已经在使用导航组件,则可以使用它。(个人意见,如果您尚未使用导航组件,您应该迁移到它,因为它非常容易使用。请相信一个曾试图自行管理后退堆栈的人的话)
您可以选择需要在导航图中进行分组的所有片段,并执行 右键单击->移动到嵌套图->新建图
现在,这将会将所选片段移动到主导航图内的嵌套图中,如下所示:
<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>
现在,在片段中初始化ViewModel时,请执行以下操作
val viewModel: CheckoutViewModel by navGraphViewModels(R.id.checkout_graph)
val viewModel: CheckoutViewModel by navGraphViewModels(R.id.checkout_graph) { viewModelFactory }
请确保它是 R.id.graph
而不是 R.navigation.graph
由于某种原因,创建导航图并使用 include
将其嵌套在主导航图中对我没有起作用。可能是个错误。
感谢Manually clearing an Android ViewModel? 指引我朝正确方向。
DialogFragment
提供了错误的片段管理器。
在我的情况下,它应该按照以下方式工作:class MyDialog : DialogFragment() {
private val viewModel: MyViewModel by viewModels({ requireParentFragment() })
在我的fragment
中初始化对话框:
private fun showDialog(){
MyDialog().show(childFragmentManager, "AddFriendToGroupDialog")
}
我正在使用 implementation 'androidx.fragment:fragment-ktx:1.3.0'
和导航图。
我遇到了同样的问题,尝试了以上所有解决方案但在我的情况下都不起作用,我想到了另一种解决方案,使用requireParentFragment()返回子片段中的NavHostFragment并解决了问题。
private val viewModel: childViewModel by viewModels(
ownerProducer = { requireParentFragment().childFragmentManager.primaryNavigationFragment!! }
)
private val viewModel: MyOrdersVM by viewModels()
使用 Kotlin 和延迟初始化(又称 by viewModels
)的版本
在父 Fragment 中(例如 ViewPager2)
private val viewModel: MyViewModel by viewModels({ this }) {
TODO("MyViewModelFactory instance")
}
在子片段中(例如ViewPager2中的页面)
private val viewModel: MyViewModel by viewModels({ requireParentFragment() })
this
,它也能正常工作。在viewModels()中,默认会传递this
。顺便说一句,谢谢,它运行得很好。 - Pratik Saluja我也遇到了这个问题。为子片段创建了一个新的ViewModel。 问题在于getParentFragment()返回NavHostFragment而不是所需的片段。
我们需要在子片段中获取真正的父对象。
如果我们执行requireParentFragment().requireParentFragment(),那么我们就可以得到真正的父对象。
解决方案:(用于子更新)
Fragment parent = requireParentFragment().requireParentFragment();
viewModel = new ViewModelProvider(parent).get(RequestViewModel.class);
ViewModels
的哈希码,以验证它们是否被共享。如果它们是相同的,那么它们就是被共享的。同时,还要检查子Fragment的子Fragment,这可能是原因。 - Jeel Vankhede