从FragmentManager取回的Fragment偶现RecyclerView Adapter为null问题咨询
问题原因分析
该偶现空值问题的触发根源和Activity配置变更、Fragment生命周期、异步任务执行时序直接相关,具体触发点如下:
- Fragment状态未持久化保存:你没有重写
NewsFeedFragment的onSaveInstanceState方法存储列表数据,当系统因配置变更(屏幕旋转、语言切换、暗黑模式切换等)销毁重建Fragment时,mNewsPageAdapter作为非序列化的普通类成员变量会被自动清空 - 异步任务和生命周期不同步:
LoadFirstPageTask是异步执行的网络请求,当你从FragmentManager取回旧实例调用replace方法时,Fragment的onActivityCreated生命周期会先执行,此时异步任务还未完成拉数、初始化Adapter的逻辑,自然会读到null值 - 不必要的replace操作触发生命周期重走:你在Activity恢复时,不管取到的Fragment是不是已经附着在容器上,都会强行调用一次
replace,该操作会让Fragment重新走一遍视图销毁、重建的生命周期,已经初始化的Adapter也会被清空 - 额外注意:
onActivityCreated方法在AndroidX Fragment 1.3.0版本后已被官方废弃,旧API本身存在状态同步不稳定的问题,也会提升该问题的出现概率
修复方案
- 补充Fragment状态保存逻辑,在
NewsFeedFragment中重写onSaveInstanceState,把列表数据序列化后存入Bundle:
@Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); // 提前确保你的新闻数据类已实现Parcelable接口 if (mNewsPageAdapter != null && !mNewsPageAdapter.getData().isEmpty()) { outState.putParcelableArrayList("news_list", new ArrayList<>(mNewsPageAdapter.getData())); } }
- 迁移生命周期逻辑到官方推荐的
onViewCreated中,优先从恢复的Bundle中初始化Adapter,避免不必要的重复请求:
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // 先完成RecyclerView、LayoutManager的基础初始化,此处省略你原有逻辑 if (savedInstanceState != null && savedInstanceState.containsKey("news_list")) { List<News> savedNews = savedInstanceState.getParcelableArrayList("news_list"); mNewsPageAdapter = new NewsPageAdapter(savedNews); setupRecyclerView(savedInstanceState); } else { new LoadFirstPageTask().execute(); } }
- 优化Activity的Fragment恢复逻辑,避免重复执行replace操作:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.id.your_activity_layout); if (savedInstanceState != null) { mPageToLoad = savedInstanceState.getString("pageToLoad"); if (mPageToLoad != null) { NewsFeedFragment existing = (NewsFeedFragment) getSupportFragmentManager().findFragmentByTag(mPageToLoad); // 仅当Fragment不存在时才创建新实例,已存在的实例会自动恢复不需要重复replace if (existing == null) { setFragment(mPageToLoad, null); } } } else { // 补充你原有首次启动时的Fragment初始化逻辑 } }
内容的提问来源于stack exchange,提问作者Michael J
相关产品推荐
相关产品推荐

