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

Android切换深浅色模式时ViewPager2内嵌Fragment根视图引用丢失问题

问题根因
  • 深浅色切换属于Android系统配置变更,默认会触发Activity及所有依附的Fragment销毁重建,你代码中多处错误的缓存逻辑导致后续操作的都是销毁前的旧Fragment实例,其绑定的根视图已经被回收,因此出现引用丢失问题。
  • 具体错误点:
    • 把viewPager、pagerAdapter声明为static,配置变更后依然持有旧实例,造成内存泄漏同时逻辑异常
    • 在MyPagerAdapter中提前缓存3个子Fragment实例,配置变更后系统会自动重建新的子Fragment,你缓存的旧实例早已和视图解绑
    • 调用pagerAdapter.createFragment()获取子Fragment实例,这个方法的作用是创建新的Fragment实例,不是获取当前已经 attach 到页面的正在显示的实例,拿到的永远是你提前缓存的无效旧实例
修复步骤

1. 移除错误的static声明和Fragment缓存逻辑

主Fragment中删除viewPager、pagerAdapter的static修饰符,修改MyPagerAdapter不要提前缓存子Fragment:

// 原错误static声明修改为普通成员变量
public ViewPager2 viewPager;
public MyPagerAdapter pagerAdapter;

public static class MyPagerAdapter extends FragmentStateAdapter {
    public MyPagerAdapter(FragmentActivity fa) {
        super(fa);
    }

    @NonNull
    @Override
    public Fragment createFragment(int pos) {
        // 每次创建新实例即可,FragmentStateAdapter会自行管理生命周期
        switch (pos) {
            case 0: return DisplayScoresFragment.newInstance(1, false);
            case 1: return DisplayScoresFragment.newInstance(2, false);
            case 2: return DisplayScoresFragment.newInstance(3, false);
            default: return DisplayScoresFragment.newInstance(1, false);
        }
    }

    @Override
    public int getItemCount() {
        return NUM_PAGES;
    }
}

2. 新增从FragmentManager获取当前存活子Fragment的方法

不要调用createFragment拿实例,从getChildFragmentManager中获取系统自动重建的当前正在显示的子Fragment:

// 主Fragment新增方法
private DisplayScoresFragment getFragmentAtPosition(int position) {
    // ViewPager2的FragmentStateAdapter默认生成的Fragment tag格式为f + itemId
    return (DisplayScoresFragment) getChildFragmentManager().findFragmentByTag("f" + pagerAdapter.getItemId(position));
}

3. 修改setAllChecked方法,使用正确的实例获取逻辑

public void setAllChecked(boolean v) {
    for (int i = 0; i < NUM_PAGES; i++) {
        DisplayScoresFragment fragment = getFragmentAtPosition(i);
        // 实例为空说明还没初始化,跳过即可,后续初始化时会自动读取最新状态
        if (fragment != null) {
            fragment.check = v;
            fragment.reloadModes(false);
        }
    }
    viewPager.setCurrentItem(viewPager.getCurrentItem());
}

4. 子Fragment增加空判断避免崩溃

子Fragment的reloadModes方法增加视图有效性判断,避免视图未初始化时调用报错:

public void reloadModes() {
    if (root != null && root.isAttachedToWindow()) {
        init(root, mode, true);
    }
}
public void reloadModes(boolean v) {
    if (root != null && root.isAttachedToWindow()) {
        init(root, mode, v);
    }
}
// 可选优化:在onDestroyView中把root置空,避免持有旧视图引用
@Override
public void onDestroyView() {
    super.onDestroyView();
    root = null;
    pullToRefresh = null;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 21:36:04