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 而不是片段。
我正在遵循 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 而不是片段。