如何为父片段和子片段提供相同的 ViewModel 实例
How to give same instance of ViewModel to both the Parent and Child fragment
有两个片段:ParentFragment 和 ChildFragment。
ChildFragment
已添加到 ParentFragment
的视图中。
现在对 Android 使用 Dagger2
有 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
的两个独立实例,因为它们接收两个不同的片段实例。
我们如何使它return成为同一个实例,以便数据可以在父片段和子片段之间共享?
我尝试在 ChildFragmentModule
中传递 ParentFragment
而不是 ChildFragment
,但这会导致 Dagger 依赖注入错误。
用 Activity
范围创建您的 ViewModel
。然后 Activity
中的所有 Fragment
将获得相同的 ViewModel
实例。
查看官方 ViewModelProviders 参考资料。您可以使用 Activity
和 Fragment
范围创建 ViewModel
。
ViewModelProvider of (FragmentActivity activity)
Creates a ViewModelProvider, which retains ViewModels while a scope of given Activity is alive. More detailed explanation is in ViewModel.
和
ViewModelProvider of (Fragment fragment)
Creates a ViewModelProvider, which retains ViewModels while a scope of given fragment is alive. More detailed explanation is in ViewModel.
用于创建 ViewModel
的示例代码
来自 Activity:
movieListViewModel = ViewModelProviders.of(this).get(MovieListViewModel.class);
来自片段:
movieListViewModel = ViewModelProviders.of(getActivity()).get(MovieListViewModel.class);
使用Fragment-ktx我们可以像In **ParentFragment**
那样做
private val viewModel: DemoViewModel by viewModels()
和
In ChildFragment
private val viewModel: DemoViewModel by viewModels(
ownerProducer = { requireParentFragment() }
)
这样做我们可以在 ParentFragment 和 ChildFragment[ 中获得相同的 ViewModel 实例
在app中添加依赖 -> build.gralde
implementation 'androidx.fragment:fragment-ktx:1.1.0
在您的 应用中实施 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()})
我在所有解决方案中都遇到了同样的问题,但在我的场景中没有工作想出另一个解决方案,使用 requireParentFragment() return NavHostFragment in child fragment 通过使用
解决它
private val viewModel: childViewModel by viewModels(
ownerProducer = { requireParentFragment().childFragmentManager.primaryNavigationFragment!! }
)
在Parent Fragmet中使用这个
private val viewModel: MyOrdersVM by viewModels()
ViewModelProvider
构造函数有 owner
参数
ViewModelProvider(
ViewModelStoreOwner owner,
ViewModelProvider.Factory factory
)
此参数负责 ViewModel
实例保持不变的范围。您需要在 ViewModelStoreOwner
上传递相同的引用才能拥有 ViewModel
的相同实例
如果在两个相互依赖的片段之间共享 ViewModel
作为父子,您需要像这样获取 ViewModel
实例:
在父片段:
viewModel = ViewModelProvider(
this,
viewModelFactory
).get(ProfileViewModel::class.java)
在子片段:
viewModel = ViewModelProvider(
requireParentFragment(),
viewModelFactory
).get(ProfileViewModel::class.java)
This resource 可能有助于了解更多信息。
有两个片段:ParentFragment 和 ChildFragment。
ChildFragment
已添加到 ParentFragment
的视图中。
现在对 Android 使用 Dagger2
有 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
的两个独立实例,因为它们接收两个不同的片段实例。
我们如何使它return成为同一个实例,以便数据可以在父片段和子片段之间共享?
我尝试在 ChildFragmentModule
中传递 ParentFragment
而不是 ChildFragment
,但这会导致 Dagger 依赖注入错误。
用 Activity
范围创建您的 ViewModel
。然后 Activity
中的所有 Fragment
将获得相同的 ViewModel
实例。
查看官方 ViewModelProviders 参考资料。您可以使用 Activity
和 Fragment
范围创建 ViewModel
。
ViewModelProvider of (FragmentActivity activity)
Creates a ViewModelProvider, which retains ViewModels while a scope of given Activity is alive. More detailed explanation is in ViewModel.
和
ViewModelProvider of (Fragment fragment)
Creates a ViewModelProvider, which retains ViewModels while a scope of given fragment is alive. More detailed explanation is in ViewModel.
用于创建 ViewModel
来自 Activity:
movieListViewModel = ViewModelProviders.of(this).get(MovieListViewModel.class);
来自片段:
movieListViewModel = ViewModelProviders.of(getActivity()).get(MovieListViewModel.class);
使用Fragment-ktx我们可以像In **ParentFragment**
private val viewModel: DemoViewModel by viewModels()
和
In ChildFragment
private val viewModel: DemoViewModel by viewModels(
ownerProducer = { requireParentFragment() }
)
这样做我们可以在 ParentFragment 和 ChildFragment[ 中获得相同的 ViewModel 实例
在app中添加依赖 -> build.gralde
implementation 'androidx.fragment:fragment-ktx:1.1.0
在您的 应用中实施 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()})
我在所有解决方案中都遇到了同样的问题,但在我的场景中没有工作想出另一个解决方案,使用 requireParentFragment() return NavHostFragment in child fragment 通过使用
解决它private val viewModel: childViewModel by viewModels(
ownerProducer = { requireParentFragment().childFragmentManager.primaryNavigationFragment!! }
)
在Parent Fragmet中使用这个
private val viewModel: MyOrdersVM by viewModels()
ViewModelProvider
构造函数有 owner
参数
ViewModelProvider(
ViewModelStoreOwner owner,
ViewModelProvider.Factory factory
)
此参数负责 ViewModel
实例保持不变的范围。您需要在 ViewModelStoreOwner
上传递相同的引用才能拥有 ViewModel
如果在两个相互依赖的片段之间共享 ViewModel
作为父子,您需要像这样获取 ViewModel
实例:
在父片段:
viewModel = ViewModelProvider(
this,
viewModelFactory
).get(ProfileViewModel::class.java)
在子片段:
viewModel = ViewModelProvider(
requireParentFragment(),
viewModelFactory
).get(ProfileViewModel::class.java)
This resource 可能有助于了解更多信息。