代码之家  ›  专栏  ›  技术社区  ›  mhtmalpani

如何为父片段和子片段提供相同的ViewModel实例

  •  19
  • mhtmalpani  · 技术社区  · 6 年前

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

    现在使用 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 因为他们收到两个不同的片段实例。

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

    我试过通过考试 父片段 而不是 儿童碎片 ChildFragmentModule ,但这会导致匕首依赖注入错误。

    5 回复  |  直到 6 年前
        1
  •  26
  •   Abu Yousuf    6 年前

    创建你的 ViewModel 具有 Activity 范围然后全部 Fragment 在这里面 活动 也会一样 视图模型 例子

    检查官员 ViewModelProviders 参考你可以创造 视图模型 两者都有 活动 碎片 范围

    ViewModelProvider of (FragmentActivity activity)
    

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

    ViewModelProvider of (Fragment fragment)
    

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

    用于创建 视图模型

    从活动中:

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

    来自片段:

     movieListViewModel = ViewModelProviders.of(getActivity()).get(MovieListViewModel.class);
    
        2
  •  17
  •   Alok Mishra    4 年前

    使用 Fragment-ktx 我们可以照你说的做 In **ParentFragment**

     private val viewModel: DemoViewModel by viewModels()
    

    In ChildFragment

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

    这样我们就可以得到相同的 视图模型 在里面 父片段 儿童碎片

    在中添加依赖项 应用程序->建筑格拉尔德

    implementation 'androidx.fragment:fragment-ktx:1.1.0
    
        3
  •  3
  •   Ndriçim Sadiku    4 年前

    使生效 片段ktx 在你的 应用程序->建筑格拉德尔 :

    implementation 'androidx.fragment:fragment-ktx:1.2.5
    

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

    在parentFragment中,可以获得如下视图模型:

    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()})
    
        4
  •  1
  •   Abdul Wahab    4 年前

    我有一个同样的问题,首先尝试了所有的解决方案,但在我的场景中不起作用。使用requireParentFragment()在子片段中返回NavHostFragment,然后使用

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

    在父Fragmet中使用此

    private val viewModel: MyOrdersVM by viewModels()
    
        5
  •  0
  •   Joe Dow    2 年前

    ViewModelProvider 构造函数 owner 参数

    ViewModelProvider(
        ViewModelStoreOwner owner,
        ViewModelProvider.Factory factory
    )
    

    参考 official docs.

    此参数负责以下范围: ViewModel 实例将保持不变。你需要传递相同的参考 ViewModelStoreOwner 有同样的例子 视图模型

    以防分享 视图模型 在作为父子依赖的两个片段中,您需要 视图模型 例如:

    在父片段:

    viewModel = ViewModelProvider(
      this, 
      viewModelFactory
    ).get(ProfileViewModel::class.java) 
    

    在子片段:

    viewModel = ViewModelProvider(
      requireParentFragment(), 
      viewModelFactory
    ).get(ProfileViewModel::class.java) 
    

    This resource 了解更多可能会有所帮助。