ViewPager2/Tabs ViewModel 状态问题

ViewPager2/Tabs problem with ViewModel state

我正在遵循 MVVM 模式 - 这意味着我为每个片段都有一个 ViewModel。

我使用 ViewPager2 添加了两个 标签。

我的适配器是这样的:

@Override
public Fragment createFragment(int position) {
    switch (position) {
        case 0:
            return new MergedItemsFragment();
        case 1:     
            return new ValidatedMergedItemsFragment();
    }
    return new MergedItemsFragment();
}

选项卡正在运行。但是,我注意到我的 MergedItemsFragment 的 ViewModel 行为异常。 在添加选项卡之前,我像这样导航到片段:

NavHostFragment.findNavController(this).navigate(R.id.action_roomFragment_to_itemsFragment);

当我用 NavHostFragment.findNavController(this).popBackStack() 离开那个片段,然后 return 编辑到那个片段时,我会得到一个新的空 ViewModel。 这是有意的。

使用新方法,我正在使用 return new MergedItemsFragment() 进行导航。当我离开该片段并稍后在 return 时,我得到一个 包含旧数据 的 ViewModel。这是一个问题,因为旧数据不再相关,因为用户在另一个片段中选择了不同的数据。


更新#1

我意识到他实际上将 all 旧的 Fragments 保留在内存中,因为多次调用相同的打印语句。它被调用的次数随着我离开和 return 进入该屏幕的次数而增加。因此,如果我离开 return 10 次并旋转我的设备,他实际上会执行一行 10 次。 任何猜测如何以与 ViewModels 一起工作的方式使用导航组件实现 Tabs/ViewPagers?


更新 #2

我这样设置我的 ViewModels:

viewModel = new ViewModelProvider(this, providerFactory).get(MergedItemViewModel.class)

我得到相同的结果:

viewModel = ViewModelProviders.of(this).get(MergedItemViewModel.class);

我在 Fragment 本身中绑定了 ViewModel。因此,this 是片段。

根据您的评论,您正在使用 Fragment,并且在该 Fragment 中有您的 viewpager。 因此,在为 ViewPager 创建适配器时,您需要传递 childFragmentManager 而不是 getActivity()

下面是您可以使用的 viewPager 适配器示例

class NewViewPagerAdapter(fm: FragmentManager, behavior: Int) : FragmentStatePagerAdapter(fm, behavior) {
    private val mFragmentList: MutableList<Fragment> = ArrayList()
    private val mFragmentTitleList: MutableList<String> = ArrayList()

    override fun getItem(position: Int): Fragment {
        return mFragmentList[position]
    }

    override fun getCount(): Int {
        return mFragmentList.size
    }

    fun addFragment(fragment: Fragment, title: String) {
        mFragmentList.add(fragment)
        mFragmentTitleList.add(title)
    }

    override fun getPageTitle(position: Int): CharSequence? {
        return mFragmentTitleList[position]
    }
}

并且在创建您的适配器时像这样调用它

   val adapter = NewViewPagerAdapter(
        childFragmentManager,
        FragmentPagerAdapter.POSITION_UNCHANGED
    )

好像您看到了 FragmentStatePagerAdapter 的文档,它指出您应该在适配器的构造函数中传递 (FragmentManager, int)

我希望这能解决您的问题,因为有一天我遇到了同样的问题。

编码愉快。

new ViewModelProvider(requireActivity()).get("your_key", YourViewModel.class)

使用 requireActivity 获取 ViewModel 而不是片段。