简体   繁体   English

ViewPager2/Tabs 的 ViewModel 状态问题

[英]ViewPager2/Tabs problem with ViewModel state

I am following the MVVM pattern - meaning I have a ViewModel for each Fragment.我遵循 MVVM 模式 - 这意味着我为每个 Fragment 都有一个 ViewModel。

I added two tabs by using ViewPager2.我使用 ViewPager2 添加了两个选项卡。

My adapter looks like this:我的适配器看起来像这样:

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

The tabs are working.选项卡正在工作。 However, I noticed that the ViewModel of my MergedItemsFragment is behaving weirdly.但是,我注意到我的 MergedItemsFragment 的 ViewModel 表现得很奇怪。 Before I added tabs I navigated to the Fragment like this:在我添加标签之前,我像这样导航到 Fragment:

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

When I left that fragment with NavHostFragment.findNavController(this).popBackStack() and later on returned to that fragment I would get a new empty ViewModel.当我用NavHostFragment.findNavController(this).popBackStack()离开那个片段然后返回到那个片段时,我会得到一个新的空 ViewModel。 This was intended.这是有意的。

With the new approach I am navigating with return new MergedItemsFragment() .使用新方法,我使用return new MergedItemsFragment()导航。 When I leave that fragment and later on return I am getting a ViewModel that contains the old data .当我离开那个片段并稍后返回时,我得到一个包含旧数据的 ViewModel 。 That is an issue because the old data is not relevant anymore because the User selected different data in another fragment.这是一个问题,因为旧数据不再相关,因为用户在另一个片段中选择了不同的数据。


Update #1更新 #1

I realized that he actually keeps all the old Fragments in memory because the same print statements gets called multiple times.我意识到他实际上将所有片段保存在内存中,因为多次调用相同的打印语句。 The times it is called increases with the amount of times I leave and return to that screen.它被调用的次数随着我离开并返回该屏幕的次数而增加。 So if I leave and return 10 times and rotate my device he will actually execute one line 10 times.因此,如果我离开并返回 10 次并旋转我的设备,他实际上会执行一行 10 次。 Any guesses how to implement Tabs/ViewPagers with Navigation Components in a manner that works with ViewModels?任何猜测如何以与 ViewModels 一起工作的方式使用导航组件实现 Tabs/ViewPagers?


Update #2更新 #2

I set my ViewModels like this:我这样设置我的 ViewModel:

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

I get the same results with:我得到相同的结果:

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

I bind the ViewModel in the Fragment itself.我在 Fragment 本身中绑定了 ViewModel。 Therefore, this is the Fragment.因此, this就是 Fragment。

As per your comment, you are using Fragment and inside that Fragment there is your viewpager.根据您的评论,您正在使用 Fragment 并且在该 Fragment 中有您的 viewpager。 So while creating your Adapter for ViewPager you need to pass childFragmentManager instead of getActivity()因此,在为 ViewPager 创建适配器时,您需要传递childFragmentManager而不是getActivity()

Below is a sample Adapter for your viewPager that you can use以下是您可以使用的 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]
    }
}

and while creating your adapter call it like在创建您的适配器时调用它

   val adapter = NewViewPagerAdapter(
        childFragmentManager,
        FragmentPagerAdapter.POSITION_UNCHANGED
    )

as if you see the documentation for FragmentStatePagerAdapter it states that you should pass (FragmentManager, int) inside your adapter's constructor就像您看到FragmentStatePagerAdapter的文档一样,它指出您应该在适配器的构造函数中传递(FragmentManager, int)

I hope this will solve your issue as I was facing the same issue one day.我希望这能解决您的问题,因为有一天我遇到了同样的问题。

Happy coding.快乐编码。

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM