ViewPager滑动切换Fragment时RecyclerView Adapter数据丢失异常排查
问题分析与解决方案
核心原因
FragmentStatePagerAdapter(及ViewPager2的FragmentStateAdapter)会自动销毁非活跃的Fragment(默认保留当前页前后各1个),当Fragment被重建时,RecyclerView的Adapter可能与当前Fragment的数据源imageSet引用脱节:
- 原Adapter持有的是旧Fragment中数据源的引用,重建后的Fragment里
imageSet是新实例,导致Adapter的getItemCount()返回0,但当前Fragment的imageSet实际有数据; - 若Fragment重建时未正确恢复数据源,或Adapter未同步更新引用,滚动RecyclerView时就会触发
IndexOutOfBound异常。
你的临时方案(重新设置Adapter)有效,本质是让RecyclerView重新绑定当前Fragment的imageSet数据源,但这不是最优解,以下是更合理的处理方式:
具体解决方案
1. 让RecyclerView Adapter持有数据源的实时引用
不要在Adapter初始化时拷贝数据源,而是直接持有引用,并提供更新方法同步数据:
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder> { private List<String> mImageData; // 构造方法传入数据源引用 public ImageAdapter(List<String> imageData) { this.mImageData = imageData; } // 提供更新数据源的方法 public void updateData(List<String> newData) { this.mImageData = newData; notifyDataSetChanged(); // 通知RecyclerView刷新 } @Override public int getItemCount() { return mImageData == null ? 0 : mImageData.size(); } // ViewHolder及绑定逻辑省略 }
2. 在Fragment恢复时同步Adapter数据源
在Fragment的onResume或onViewCreated中,复用已有Adapter并更新其数据源,而非每次重建都新建Adapter:
private ImageAdapter mImageAdapter; private List<String> imageSet; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_image_list, container, false); RecyclerView recyclerView = view.findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); // 初始化Adapter,绑定当前imageSet mImageAdapter = new ImageAdapter(imageSet); recyclerView.setAdapter(mImageAdapter); return view; } @Override public void onResume() { super.onResume(); // 确保Adapter数据源与当前Fragment的imageSet同步 if (mImageAdapter != null) { mImageAdapter.updateData(imageSet); } }
3. 确保Fragment重建时数据源正确恢复
当Fragment因ViewPager销毁重建时,通过onSaveInstanceState保存数据源,在onCreate中恢复:
@Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); // 保存当前数据源 outState.putStringArrayList("image_set", new ArrayList<>(imageSet)); } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { // 恢复之前保存的数据源 imageSet = savedInstanceState.getStringArrayList("image_set"); } else { // 首次创建时加载初始数据 imageSet = loadInitialImageData(); } }
4. ViewPager2的适配处理
ViewPager2使用FragmentStateAdapter,销毁重建逻辑与ViewPager一致,只需沿用上述Adapter和Fragment的处理方式即可,无需额外修改。
为什么临时方案有效?
重新设置Adapter相当于为RecyclerView绑定了当前Fragment最新的imageSet引用,让getItemCount()能正确返回数据量。但频繁创建Adapter会导致不必要的对象开销,复用Adapter并更新数据的方式性能更优。
内容的提问来源于stack exchange,提问作者MJM
相关产品推荐
相关产品推荐

