You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ViewPager2的FragmentStateAdapter增删Fragment时无法更新问题

ViewPager2动态增删Fragment问题修复

问题根源拆解

  1. "Fragment already added"错误:

    • 初始化阶段若prefsPor不为空,已添加过Favoritos片段,后续调用addFragment时重复添加同类型/同实例Fragment,触发FragmentManager重复添加检查。
    • 每次调用addFragment都重新创建并绑定TabLayoutMediator,导致重复绑定引发冲突。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:02:17