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

如何使用FragmentStateAdapter和ViewPager2阻止切换Tab时Fragment刷新

解决ViewPager2 + FragmentStateAdapter切换Tab时Fragment重建的问题

问题根源分析

你的代码存在两个核心问题,直接导致Fragment切换时重建:

  1. getItemId实现错误:你用Fragment的hashCode作为Item ID,但Fragment的hashCode并非固定值,ViewPager2会通过对比Item ID判断是否需要重新创建Fragment,ID变化就会触发重建操作。
  2. Adapter设置时机错误:先给ViewPager2绑定Adapter,再往Adapter里添加Fragment,导致Adapter初始化时数据为空,后续添加数据后触发不必要的视图重建。

修复步骤

1. 修正Adapter的getItemId方法

将getItemId改为返回固定的位置ID(如果Fragment列表不会动态增删),保证每个位置的ID唯一且不变:

public class LandingAdapter extends FragmentStateAdapter {

    private final List<Fragment> mFragmentList = new ArrayList<>();

    public LandingAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
        super(fragmentManager, lifecycle);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getItemCount() {
        return mFragmentList.size();
    }

    public void addFragment(Fragment fragment) {
        mFragmentList.add(fragment);
    }

    @Override
    public long getItemId(int position) {
        // 返回固定的位置ID,避免因Fragment实例变化导致ID改变
        return position;
    }

    // 可选:如果需要支持动态修改Fragment列表,需重写该方法
    @Override
    public boolean containsItem(long itemId) {
        return itemId >= 0 && itemId < mFragmentList.size();
    }
}

2. 调整Activity中Adapter的初始化顺序

先完成Fragment的添加,再将Adapter绑定到ViewPager2:

ViewPager2 mViewPager = findViewById(R.id.ViewPager);
TabLayout mTabLayout = findViewById(R.id.TabLayout);

LandingAdapter mAdapter = new LandingAdapter(getSupportFragmentManager(), getLifecycle());
int savedAppMode = SharedPrefs.getInt(this, "app_mode_checked_item",0);
if (savedAppMode == 1) {
    mAdapter.addFragment(new ItemsFrag1());
    mAdapter.addFragment(new ContactsFrag1());
    mAdapter.addFragment(new ImagesFrag1());
} else {
    mAdapter.addFragment(new ItemsFrag2());
    mAdapter.addFragment(new ContactsFrag2());
    mAdapter.addFragment(new ImagesFrag2());
}
// 先填充数据再绑定Adapter
mViewPager.setAdapter(mAdapter);

// 可选:设置缓存页面数,让所有Tab的Fragment都保持在内存中(根据需求调整)
mViewPager.setOffscreenPageLimit(2);

new TabLayoutMediator(mTabLayout, mViewPager, (tab, position) -> {
    switch (position) {
        case 0:
            tab.setText("Items");
            tab.setIcon(R.drawable.x_icon_photo);
            break;
        case 1:
            tab.setText("Contacts");
            tab.setIcon(R.drawable.x_icon_video);
            break;
        case 2:
            tab.setText("Images");
            tab.setIcon(R.drawable.x_icon_download);
            break;
    }
}).attach();

额外说明

  • setOffscreenPageLimit设置的是当前页面左右两侧需要缓存的页面数,设置为2时,三个Tab的Fragment都会被缓存,切换时不会重建。
  • 如果需要动态修改Fragment列表,不要直接修改mFragmentList,需调用Adapter的notifyDataSetChanged(),同时保证getItemId返回的ID能唯一标识每个Fragment(比如给每个Fragment分配固定的唯一ID,而非依赖position)。

内容的提问来源于stack exchange,提问作者user13926345

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 02:35:03