当在 Android 设备的设置应用程序中更改字体大小时,将重新创建 Activity。此时,当从 Activity 访问 Fragment 的功能时,requireContext() 和 requireView() 为 null,并且未启动 viewModel。
这是我的代码
活动
var pagerAdapter: NewPagerAdapter? = null
fun initView(){
val vpContent = findViewById<ViewPager2>(R.id.vp_content)
val fragmentList = ArrayList<ParentFragment>()
fragmentList.add(FristFragment())
fragmentList.add(SecondFragment())
fragmentList.add(ThirdFragment())
pagerAdapter = NewPagerAdapter(fragmentList, supportFragmentManager, lifecycle)
vpContent.adapter = pagerAdapter
val btnRefresh = findViewById<Button>(R.id.btn_scm_refresh)
btnRefresh.setOnClickListener {
(pagerAdapter)!!.allRefreshPage()
}
}
适配器
override fun getItemCount(): Int {
return fragmentList.size
}
override fun createFragment(position: Int): Fragment {
return fragmentList[position]
}
fun allRefreshPage(context: Context){
for(i in 0 until fragmentList.size){
fragmentList[i].refreshData()
}
}
父片段
abstract class ParentFragment : Fragment() {
abstract fun refreshData()
}
子片段
private lateinit var viewModel: NewViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(this, ViewModelFactory())[NewViewModel::class.java]
}
override fun refreshData() {
if(context == null || view == null) {
Log.w(TAG, "refreshData: have not context or view")
return
}
viewModel.initAppList(requireContext(), requireView())
}
为什么会出现这种情况?
如何确保 null 不会出现?
还有其他方法可以将其作为活动中片段的函数来处理吗?
1/为什么会发生这种情况?
PagerAdapter的fragmentList只保存Fragment实例以在需要时设置数据,不应该使用fragment变量来更新UI。尽管片段已启动,但它尚未附加到活动(用户尚未将选项卡滚动到该位置)。如果未附加
Fragment
,则 getContext
或 getActivity
始终为空
您的
ViewModel
可能没有创建在正确的位置,如Fragment的onCreate文档中所述:
请注意,这可以在片段的活动仍在时调用 被创造的过程。因此,您不能依赖诸如 此时活动的内容视图层次结构正在初始化
阅读此参考资料
2/如何确保不会出现null?
正如我所说,不要使用Adapter中的Fragment列表来更新Fragment的数据,这可能会触发UI更新
3/是否有其他方法可以将其作为活动中片段的函数来处理?
a/ 您应该使用
by activityViewModels
委托来创建 ViewModel 以避免在错误的位置创建 ViewModel,并且 activityViewModels
将确保您的 ViewModel 附加到 Activity 实例,Activity 和 Fragment 都为您提供相同的 ViewModel 实例这样您就可以在 Activity
和 Fragment
之间共享数据
private val viewModel by activityViewModels<TextClassifyViewModel>()
b/ 将数据存储在
LiveData
内的ViewModel
中,然后从Fragment
中观察。这样,每次重新创建 Fragment 时,LiveData
都会再次触发数据以使视图保持最新。无需每次都打电话refreshData
。