求助:使用activityViewModels()时触发Fragment未关联Activity异常
问题根源
activityViewModels()依赖Fragment与Activity的绑定关系,当你的ViewPager子Fragment(尤其是被预加载的那些)还没执行onAttach()生命周期方法时,就直接在类成员位置初始化ViewModel,就会触发这个异常。ViewPager默认会预加载左右相邻的Fragment,这些预加载的Fragment实例创建后还没attach到Activity,但成员变量的初始化会在实例创建时就执行,早于onAttach(),自然报错。
解决方案
1. 延迟ViewModel初始化到Fragment已attach后
把ViewModel的初始化从类成员位置移到onAttach()或onViewCreated()这类生命周期方法里,用lateinit var实现:
private lateinit var dataViewModel: DataViewModel override fun onAttach(context: Context) { super.onAttach(context) dataViewModel = ViewModelProvider(requireActivity())[DataViewModel::class.java] }
也可以用lazy配合isAdded检查,确保只有Fragment已attach时才初始化:
private val dataViewModel: DataViewModel by lazy { check(isAdded) { "Fragment必须绑定到Activity才能获取ViewModel" } ViewModelProvider(requireActivity())[DataViewModel::class.java] }
2. 调整ViewPager预加载策略(可选)
如果业务不需要预加载,可关闭ViewPager的预加载,避免未attach的Fragment提前触发初始化:
viewPager.offscreenPageLimit = 0
不过这种方式会影响滑动流畅度,优先用第一种延迟初始化的方案。
3. 禁止在构造函数/init块中访问ViewModel
绝对不要在Fragment的构造函数、init代码块或者非生命周期回调里调用依赖Activity的API,这些时机Fragment大概率还没attach到Activity,必然触发异常。
补充说明
你之前尝试的空检查没起作用,大概率是只在使用ViewModel时做了检查,但初始化ViewModel的时机本身就早于Fragment attach,所以还是会报错。核心要保证ViewModel的初始化动作,发生在Fragment已经绑定到Activity之后。
内容的提问来源于stack exchange,提问作者sayed hassan

