代码之家  ›  专栏  ›  技术社区  ›  Jun.Grammer

重新创建活动并重新启动ViewPager2时,requireContext()和requireView()为null

  •  0
  • Jun.Grammer  · 技术社区  · 2 年前

    当Android设备的设置应用程序中的字体大小发生更改时,将重新创建活动。此时,当从活动访问片段的函数时,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()
            }
        }
    

    ParentFragment

    abstract class ParentFragment : Fragment() {
        abstract fun refreshData()
    }
    

    ChildFragment

        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())
        }
    
    
    1. 为什么会发生这种情况?

    2. 我如何确保null不会出现?

    3. 有没有其他方法可以将其作为活动中片段的函数?

    1 回复  |  直到 2 年前
        1
  •  0
  •   Tam Huynh    2 年前

    1/为什么会发生这种情况?

    PagerAdapter的fragmentList仅在需要时保存Fragment实例以设置数据,不应使用Fragment变量来更新UI。虽然片段已经启动,但它还没有附加到“活动”(用户还没有将选项卡滚动到该位置)。如果 Fragment 未连接, getContext getActivity 始终为空

    你的 ViewModel 可能无法在正确的位置创建,如Fragment的onCreate文档中所述:

    请注意,这可以在片段的活动仍在时调用 被创造的过程。因此,你不能依赖这样的东西 此时正在初始化活动的内容视图层次结构

    阅读 this reference

    2/我怎样才能确保null不会出现?

    正如我所说,不要使用适配器中的片段列表来更新片段的数据,这可能会触发UI更新。始终确保更新UI和requireContext的任何调用都在onViewCreated之后,您将在 onViewCreated onDestroyView

    3/是否有其他方法将其作为活动中片段的函数?

    a/你应该使用 by activityViewModels 委托创建ViewModel以避免在错误的位置创建ViewModel,以及 activityViewModels 将确保您的ViewModel附加到“活动”实例,“活动”和“片段”都会为您提供相同的ViewModel实例,以便您可以在之间共享数据 Activity 碎片

    private val viewModel by activityViewModels<TextClassifyViewModel>()
    

    b/将数据存储在 LiveData 在…内 ViewModel ,然后从 碎片 以这种方式,每次重新创建片段时, LiveData 将再次激发数据以使视图保持最新。不需要打电话 refreshData 每一次。

    推荐文章