ViewPager2的FragmentStateAdapter增删Fragment时无法更新问题
ViewPager2动态增删Fragment问题修复
问题根源拆解
"Fragment already added"错误:
- 初始化阶段若
prefsPor不为空,已添加过Favoritos片段,后续调用addFragment时重复添加同类型/同实例Fragment,触发FragmentManager重复添加检查。 - 每次调用
addFragment都重新创建并绑定TabLayoutMediator,导致重复绑定引发冲突。
- 初始化阶段若
IndexOutOfBoundException异常:
removeFragment未判断列表是否为空就直接执行移除操作。- 手动调用
tabLayout.removeTabAt(0),但TabLayoutMediator会自动同步Adapter数据,手动操作导致数据与Tab状态不一致。
修复后的完整实现
初始化代码
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager(), getLifecycle()); mViewPager = findViewById(R.id.viewpager); mViewPager.setAdapter(mSectionsPagerAdapter); mViewPager.setOffscreenPageLimit(mSectionsPagerAdapter.getItemCount()-1); // 仅初始化一次TabLayoutMediator,后续靠Adapter通知自动同步Tab new TabLayoutMediator(tabLayout, mViewPager, (tab, position) -> tab.setText(mSectionsPagerAdapter.getCategoryTitle(position)) ).attach();
重构后的SectionsPagerAdapter类
private class SectionsPagerAdapter extends FragmentStateAdapter { private final List<Fragment> mFragments = new ArrayList<>(); private final List<String> mCategories = new ArrayList<>(); // 内部维护分类列表,避免外部依赖 void addFragment(String title, Fragment fragment) { // 可选:避免重复添加同类型Fragment(根据业务需求调整) boolean isDuplicate = mFragments.stream() .anyMatch(frag -> frag.getClass().equals(fragment.getClass())); if (isDuplicate) { return; } mCategories.add(0, title); mFragments.add(0, fragment); notifyItemInserted(0); // 通知Adapter数据更新,TabLayout自动同步 } void removeFragment() { if (mFragments.isEmpty()) { return; // 空列表时直接返回,避免索引越界 } mCategories.remove(0); mFragments.remove(0); notifyItemRemoved(0); // 通知删除操作,TabLayout自动同步 } // 提供获取分类标题的方法,供TabLayoutMediator调用 String getCategoryTitle(int position) { return mCategories.get(position); } public SectionsPagerAdapter(FragmentManager fm, Lifecycle lifecycle) { super(fm, lifecycle); if(!prefsPor.getAll().isEmpty()) { mCategories.add(getString(R.string.fav_tab)); mFragments.add(Favoritos.newInstance(fecha)); favsCount = prefsPor.getAll().size(); } mCategories.add(getString(R.string.first_tab)); mFragments.add(General.newInstance(fecha)); mCategories.add(getString(R.string.second_tab)); mFragments.add(Deportes.newInstance(fecha)); mCategories.add(getString(R.string.third_tab)); mFragments.add(Economia.newInstance(fecha)); mCategories.add(getString(R.string.fourth_tab)); mFragments.add(Locales.newInstance(fecha)); mCategories.add(getString(R.string.fifth_tab)); mFragments.add(Internacional.newInstance(fecha)); } @NonNull @Override public Fragment createFragment(int position) { return mFragments.get(position); } @Override public int getItemCount() { return mFragments.size(); // 统一用Fragment列表长度,保证数据一致性 } }
调用addFragment的代码
// 确保每次添加的是全新Fragment实例,或根据业务逻辑判断是否需要添加 mSectionsPagerAdapter.addFragment(getString(R.string.fav_tab), Favoritos.newInstance(fecha));
核心优化点
- TabLayoutMediator仅初始化一次:Adapter通过
notify系列方法通知数据变化后,Mediator会自动同步TabLayout的标签状态,无需手动操作Tab。 - 避免Fragment重复添加:通过类型判断过滤重复Fragment,或确保每次添加全新实例。
- 空列表保护:移除操作前先检查列表是否为空,防止索引越界。
- 数据一致性:分类列表由Adapter内部维护,避免外部修改导致与Fragment列表不同步。
内容的提问来源于stack exchange,提问作者Sergio Rey
相关产品推荐
相关产品推荐

