18

有两个片段:ParentFragment 和 ChildFragment。 ChildFragment已添加到 的视图中ParentFragment

现在使用Dagger2for Android 有ParentFragmentModule一个方法:

@Provides
fun provideViewModel(fragment: ParentFragment, myViewModelFactory: MyViewModelFactory): MyViewModel {
    return ViewModelProviders.of(fragment, myViewModelFactory).get(MyViewModelImpl::class.java)
}

其中 MyViewModelFactory、MyViewModel、MyViewModelImpl 是在应用程序中创建的简单 ViewModel 逻辑。

ChildFragmentModule 具有以下方法:

@Provides
fun provideViewModel(fragment: ChildFragment, myViewModelFactory: MyViewModelFactory): MyViewModel {
    return ViewModelProviders.of(fragment, myViewModelFactory).get(MyViewModelImpl::class.java)
}

这显然是在创建两个单独的实例,ViewModel因为它们接收两个不同的片段实例。

我们如何让它返回相同的实例,以便在父片段和子片段之间共享数据?

我尝试在 中传递而ParentFragment不是,但这会导致 Dagger 依赖注入错误。ChildFragmentChildFragmentModule

4

4 回答 4

26

ViewModelActivity范围创建你的。然后其中的所有Fragment内容都Activity将获得相同的ViewModel实例。

检查官方ViewModelProviders参考。您可以ViewModel同时使用ActivityFragment范围创建。

ViewModelProvider of (FragmentActivity activity)

创建一个 ViewModelProvider,它在给定 Activity 的作用域处于活动状态时保留 ViewModel。更详细的解释在 ViewModel 中。

ViewModelProvider of (Fragment fragment)

创建一个 ViewModelProvider,它在给定片段的范围处于活动状态时保留 ViewModel。更详细的解释在 ViewModel 中。

创建示例代码ViewModel

从活动:

 movieListViewModel = ViewModelProviders.of(this).get(MovieListViewModel.class);

从片段:

 movieListViewModel = ViewModelProviders.of(getActivity()).get(MovieListViewModel.class);
于 2018-05-26T07:16:29.440 回答
16

使用Fragment-ktx我们可以这样做In **ParentFragment**

 private val viewModel: DemoViewModel by viewModels()

In ChildFragment

 private val viewModel: DemoViewModel by viewModels(
    ownerProducer = { requireParentFragment() }
)

这样做我们可以在Parent FragmentChildFragment中获得相同的ViewModel实例

在app -> build.grade中添加依赖项

implementation 'androidx.fragment:fragment-ktx:1.1.0
于 2020-07-23T06:57:10.003 回答
3

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

implementation 'androidx.fragment:fragment-ktx:1.2.5

如果您使用的是导航组件( https://developer.android.com/guide/navigation )

在 parentFragment 中,您可以像这样获取 viewModel:

private val viewModel by viewModels<DemoViewModel>()

然后,当您在 childFragment 中需要该 viewModel 时,您可以通过以下方式获得它:

private val viewModel by viewModels<DemoViewModel>({requireGrandParentFragment()})

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

fun Fragment.requireGrandParentFragment() = this.requireParentFragment().requireParentFragment()

如果您不使用导航组件

你可以像这样访问它:

private val viewModel by viewModels<DemoViewModel>({requireParentFragment()})
于 2021-01-06T13:35:46.250 回答
1

我在所有解决方案中都尝试过同样的问题,但在我的场景中不起作用提出了另一个解决方案,使用 requireParentFragment() return NavHostFragment in child fragment 通过使用解决它

private val viewModel: childViewModel by viewModels(
            ownerProducer = { requireParentFragment().childFragmentManager.primaryNavigationFragment!! }
    )

在父片段中使用这个

private val viewModel: MyOrdersVM by viewModels()
于 2021-02-01T06:18:28.640 回答