旋转后系统自动创建Fragment引发空指针,求问来源与解决方法
这个Fragment来自哪里?
没错,这个Fragment就是由FragmentManager自动创建的。当屏幕旋转这类配置变更发生时,Android系统会销毁当前Activity并重新创建它,而FragmentManager会自动保存之前已添加到Activity中的Fragment的状态(比如布局状态、实例状态),然后通过Fragment的无参构造函数重新实例化这些Fragment——这就是为什么你看到的实例hashCode和自己new的不一样,它完全是系统重建的,没有经过你手动执行的依赖注入步骤,自然就会出现依赖缺失的NullPointerException。
如何处理这种情况?
这里有几个靠谱的解决方案,按推荐程度排序:
1. 将依赖注入逻辑移到Fragment生命周期方法中
不要在new Fragment()之后立即执行注入,而是把注入逻辑放到Fragment的onAttach(Context context)或者onCreate(Bundle savedInstanceState)方法里。这样不管是你手动创建的实例,还是系统重建的实例,都会执行注入逻辑。
如果使用Dagger、Hilt这类依赖注入框架,要确保Fragment支持自动注入:
- 用Hilt的话,让Fragment添加
@AndroidEntryPoint注解即可,框架会在合适的生命周期自动完成注入; - 用Dagger的话,可以让Fragment继承
DaggerFragment,或者在onAttach里手动调用AndroidInjection.inject(this)。
2. 用ViewModel持有依赖与状态
ViewModel的生命周期独立于Activity/Fragment的配置变更,不会在旋转时被销毁。你可以把需要的依赖(比如业务Repository、网络服务)放到ViewModel中,Fragment只需要通过ViewModelProvider获取ViewModel实例即可。这样不管Fragment重建多少次,都能拿到同一个ViewModel里的依赖,从根源上避免空指针问题。
示例代码(Kotlin):
class MyViewModel @Inject constructor(private val myRepository: MyRepository) : ViewModel() { // 这里处理业务逻辑,持有依赖 } class MyFragment : Fragment() { private val viewModel: MyViewModel by viewModels() override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) // 直接使用viewModel中的myRepository,不会空指针 viewModel.myRepository.doSomething() } }
3. 在Activity中判断是否为首次创建,避免重复添加Fragment
在Activity的onCreate方法中,通过savedInstanceState是否为null来判断:如果不为null,说明是配置变更重建,此时FragmentManager已经恢复了之前的Fragment,不需要再重新new和注入。
示例代码(Java):
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState == null) { // 首次创建Activity时,才添加新Fragment并执行注入 MyFragment fragment = new MyFragment(); MyApp.getAppComponent().inject(fragment); getSupportFragmentManager().beginTransaction() .add(R.id.container, fragment, "MY_FRAGMENT_TAG") .commit(); } else { // 配置变更重建,直接获取已恢复的Fragment MyFragment fragment = (MyFragment) getSupportFragmentManager() .findFragmentByTag("MY_FRAGMENT_TAG"); // 如果用生命周期注入,这里不需要再手动注入 } }
4. 不推荐:禁止系统自动重建(谨慎使用)
你可以在AndroidManifest.xml中给Activity添加android:configChanges="orientation|screenSize",让系统不销毁重建Activity和Fragment。但这种方式需要你手动处理所有配置变更的逻辑(比如重新适配布局、更新资源),维护成本很高,也不符合Android的设计规范,除非有特殊需求,否则不推荐使用。
内容的提问来源于stack exchange,提问作者Blcknx

