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

Android:使用FragmentPagerAdapter旋转设备时出现NPE问题

解决Fragment旋转时Presenter空指针的问题

这个问题我之前也碰到过,核心原因是你对FragmentPagerAdapter的生命周期和Presenter的绑定时机理解有偏差,我来帮你梳理清楚:

为什么会出现NPE?

当屏幕旋转时,Activity会被系统重建,但FragmentPagerAdapter确实会保留之前的Fragment实例——不过这里的关键是:只有当Fragment第一次被创建时,getItem()方法才会被调用。旋转屏幕后,Adapter会直接从FragmentManager中恢复已存在的Fragment实例,不会再执行getItem()里的代码。

你原来的代码是在getItem()中创建Presenter并和Fragment绑定,这意味着:

  • 第一次启动应用时,Fragment和Presenter的绑定是正常的
  • 旋转屏幕后,恢复的Fragment没有被重新绑定Presenter,它的Presenter引用自然就是null,在onResume()调用时就触发了空指针异常

解决方案:把Presenter的初始化移到Fragment内部

正确的做法是让Fragment自己负责Presenter的创建和持有,而不是交给Adapter的getItem()方法。这样无论Fragment是第一次创建还是旋转后恢复,都能确保Presenter的引用有效。

1. 修改Fragment代码(以FragmentA为例)

public class FragmentA extends Fragment implements PresenterA.View {
    private PresenterA mPresenter;

    public static FragmentA newInstance() {
        return new FragmentA();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 在这里初始化Presenter,确保Fragment创建/恢复时都能获取到
        mPresenter = new PresenterA(this);
        
        // 进阶优化:如果需要保留Presenter的状态(比如已加载的数据),可以结合ViewModel
        // mPresenter = new ViewModelProvider(this).get(PresenterA.class);
        // 注意:此时PresenterA需要继承ViewModel类
    }

    @Override
    public void onResume() {
        super.onResume();
        // 现在这里的mPresenter肯定不为null了
        mPresenter.start();
    }

    // 实现View接口的其他方法...
}

2. 简化SectionsPagerAdapter代码

Adapter只需要负责创建Fragment实例,不需要处理Presenter的逻辑:

public class SectionsPagerAdapter extends FragmentPagerAdapter {
    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return FragmentA.newInstance();
            case 1:
                return FragmentB.newInstance();
        }
        return null;
    }

    @Override
    public int getCount() {
        return 2;
    }
}

额外优化:保留Fragment实例(可选)

如果你希望旋转屏幕时Fragment本身也不被重建,可以在Fragment的onCreate()中添加setRetainInstance(true),这样Fragment的实例会被系统保留,Presenter的引用也会一直有效:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true); // 保留Fragment实例,旋转时不会重建
    // 只在第一次创建时初始化Presenter
    if (mPresenter == null) {
        mPresenter = new PresenterA(this);
    }
}

总结

  • 不要在FragmentPagerAdapter的getItem()中绑定Presenter,这个方法仅负责Fragment的首次创建
  • 让Fragment自身管理Presenter的生命周期,确保在onCreate()或其他合适的生命周期方法中初始化Presenter
  • 结合setRetainInstance(true)或ViewModel可以更好地保留Presenter的状态,提升用户体验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:17:43