ViewPager2宿主Activity重建后首个Fragment空白无响应问题
问题根因
核心错误是FragmentStateAdapter绑定的FragmentManager层级错误,属于嵌套Fragment场景下ViewPager2的典型误用。
你在承载ViewPager2的外层WrappingFragment中初始化Adapter时,传入了宿主Activity作为FragmentStateAdapter的构造参数,这会导致ViewPager2内部的两个子Fragment被挂载到Activity级别的FragmentManager下,而非外层WrappingFragment自己的childFragmentManager。
当配置变更(语言/深色模式切换)触发Activity重建时,Activity级别的FragmentManager会独立尝试恢复它持有的所有Fragment实例,这个恢复流程和外层WrappingFragment、ViewPager2本身的重建流程不同步:
- 从日志可以看到重建阶段Fragment2重复触发了两次
onCreateView,Fragment1在最后切回选中状态时只触发了onResume,没有对应的onCreateView回调——说明旧的Fragment1实例的View已经被销毁,但FragmentManager没有将其和新Adapter创建的Fragment实例做绑定,页面位置上没有挂载有效的View层级,自然显示空白、不响应任何交互。 - Fragment2因为配置变更发生时正处于ViewPager2的选中位置,碰巧状态对齐,所以重建后可以正常显示。
修复方案
按以下步骤修改代码即可解决问题:
- 修正FragmentStateAdapter的宿主绑定
嵌套在Fragment中的ViewPager2,其FragmentStateAdapter必须直接绑定外层承载它的Fragment实例,这样Adapter会自动使用外层Fragment的childFragmentManager管理子Fragment,生命周期完全和外层Fragment对齐。
首先修改Adapter的构造方法,将原来接收FragmentActivity的参数改为接收Fragment类型宿主:
然后修改WrappingFragment中初始化Adapter的代码,传入当前外层Fragment实例作为宿主:public class MyPageAdapter extends FragmentStateAdapter { private int nr = -1; private Context context; private static final int FRAGMENT_COUNT = 2; public MyPageAdapter(@NonNull Fragment hostFragment, Context context) { super(hostFragment); this.context = context; } public MyPageAdapter(@NonNull Fragment hostFragment, int nr, Context context) { super(hostFragment); this.nr = nr; this.context = context; } // 其余原有代码保持不变 @Override public long getItemId(int position) { return super.getItemId(position); } @NonNull @Override public Fragment createFragment(int position) { if (position == 0) { return new Fragment1(); } else { return new Fragment2(); } } @Override public int getItemCount() { return FRAGMENT_COUNT; } }// 原来错误的传参:new MyPageAdapter(getActivity(), getActivity(), this); pageAdapter = new MyPageAdapter(this, requireContext()); viewPager.setAdapter(pageAdapter); - 补充View销毁时的解绑逻辑
在WrappingFragment的onDestroyView回调中清空ViewPager2的Adapter引用,避免旧View实例泄漏、加剧状态错乱:@Override public void onDestroyView() { super.onDestroyView(); // 解绑Adapter mBinding.pageTabber.setAdapter(null); // 清空Binding引用,避免持有旧View mBinding = null; }
修改完成后,ViewPager2内部的子Fragment生命周期会完全跟随外层WrappingFragment同步,配置变更触发重建时,Fragment的View创建、销毁流程会和ViewPager2状态完全匹配,不会再出现第一个Fragment空白无响应的问题,之前日志里异常的重复生命周期回调也会消失。
内容的提问来源于stack exchange,提问作者lukasniessen
相关产品推荐
相关产品推荐

