如何在BottomNavigation切换时触发ViewPager内Fragment的onCreateView
问题分析
当通过BottomNavigation切换页面时,父Fragment会被销毁视图(onDestroyView)但保留实例,再次返回时会重建视图(onCreateView)。此时ViewPager2的FragmentStateAdapter会复用之前缓存的Fragment实例,不会重新调用onCreateView,这就是问题的核心。要实现需求,需要强制让ViewPager2在父Fragment重建视图时,重新创建当前及前后各1个Fragment的视图。
解决方案
1. 修改Adapter,使其能触发Fragment重建
重写FragmentStateAdapter的getItemId和containsItem方法,引入版本号变量。每次父Fragment重建视图时更新版本号,让Adapter认为所有Fragment已失效,从而触发重建。
public class SectionsPagerAdapter extends FragmentStateAdapter { private long mVersion = 0; public SectionsPagerAdapter(@NonNull FragmentActivity fragmentActivity) { super(fragmentActivity); } // 更新版本号,触发Fragment重建 public void incrementVersion() { mVersion++; notifyDataSetChanged(); } @Override public long getItemId(int position) { // 版本号+position,确保版本更新后同一position的id变化 return position + mVersion * getItemCount(); } @Override public boolean containsItem(long itemId) { long position = itemId % getItemCount(); return position >= 0 && position < getItemCount(); } @Override public int getItemCount() { return 2000; } @NonNull @Override public Fragment createFragment(int position) { LocalDate pagerdate = LocalDate.now(); LocalDate days = pagerdate.plusDays(position - 1000); return TabTodayFragment.newInstance(days.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); } }
2. 父Fragment中重新初始化ViewPager2并触发重建
在父Fragment的onCreateView中,每次都重新初始化Adapter并更新版本号,确保当前及前后Fragment的视图被重建。
@Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = FragmentHomeBinding.inflate(inflater, container, false); View root = binding.getRoot(); SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(requireActivity()); ViewPager2 viewPager = binding.viewPager; viewPager.setAdapter(sectionsPagerAdapter); // 更新版本号,触发Fragment重建 sectionsPagerAdapter.incrementVersion(); viewPager.setOffscreenPageLimit(1); viewPager.setCurrentItem(1000, false); viewPager.post(() -> { viewPager.setCurrentItem(1000, false); sectionsPagerAdapter.notifyDataSetChanged(); }); viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { super.onPageSelected(position); LocalDate pagerdate = LocalDate.now(); LocalDate days = pagerdate.plusDays(position - 1000); String month2 = days.getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault()); String dayOfMonth2 = String.valueOf(days.getDayOfMonth()); String monthAndDay2 = month2 + " " + dayOfMonth2; binding.monthDayText.setText(monthAndDay2); } }); return root; }
3. 优化:视图销毁时清理ViewPager2
在父Fragment的onDestroyView中清空Adapter,避免内存泄漏,同时确保下次重建时不会复用旧缓存。
@Override public void onDestroyView() { super.onDestroyView(); binding.viewPager.setAdapter(null); binding = null; }
原理说明
- 通过版本号机制,让
FragmentStateAdapter认为同一位置的Fragment已失效,从而重新调用createFragment创建实例并触发onCreateView。 offscreenPageLimit=1会让ViewPager2预加载当前页面前后各1个Fragment,所以这三个Fragment的onCreateView都会被触发。- 视图销毁时清空Adapter,彻底切断旧Fragment缓存与ViewPager2的关联。
内容的提问来源于stack exchange,提问作者Unknownscl
相关产品推荐
相关产品推荐

