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

Kotlin中MVVM+LiveData实现子Fragment访问父Fragment数据遇Hilt崩溃

解决ViewPager2子Fragment获取父Fragment数据的Hilt兼容问题

问题背景

ListFragment点击列表项后,通过Bundle将数据传递到父Fragment;父Fragment通过ViewPager2包含Detail、Second两个子Fragment,需要让DetailFragment获取该数据展示。尝试通过by viewModels({requireParentFragment()})获取父Fragment的ViewModel时崩溃,报错:

Fragment DetailsFragment is not a child Fragment, it is directly attached to dagger.hilt.android.internal.managers

错误原因

ViewPager2若默认使用Activity的FragmentManager管理子Fragment,会导致子Fragment的父容器不是目标父Fragment,而是与Hilt的管理组件绑定,因此无法通过requireParentFragment()获取到预期的父Fragment实例。

解决方案

方案一:通过共享父Fragment的ViewModel(推荐)

核心是让ViewPager2的子Fragment归属于父Fragment的childFragmentManager管理,这样就能正常获取父Fragment的ViewModel。

  1. 父Fragment中正确配置ViewPager2的Adapter
    创建FragmentStateAdapter时传入父Fragment实例(内部会自动使用父Fragment的childFragmentManager):

    class ParentPagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
        override fun getItemCount(): Int = 2
    
        override fun createFragment(position: Int): Fragment {
            return when(position) {
                0 -> DetailFragment()
                1 -> SecondFragment()
                else -> throw IllegalArgumentException("Invalid position")
            }
        }
    }
    
    // 父Fragment的onViewCreated方法中初始化ViewPager2
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val viewPager = view.findViewById<ViewPager2>(R.id.view_pager)
        viewPager.adapter = ParentPagerAdapter(this)
        // 绑定TabLayout与ViewPager2的代码(略)
    }
    
  2. 父ViewModel中存储共享数据
    在MyListsViewModel中添加LiveData用于存储和分发数据:

    class MyListsViewModel : ViewModel() {
        private val _selectedList = MutableLiveData<MyListsResponse?>()
        val selectedList: LiveData<MyListsResponse?> = _selectedList
    
        fun setSelectedList(data: MyListsResponse) {
            _selectedList.value = data
        }
    }
    
  3. 父Fragment接收数据并传入ViewModel

    // 父Fragment中解析Bundle数据并传递给ViewModel
    val jsonMyLists = arguments?.getString("mylist")
    jsonMyLists?.let {
        val mylists = Gson().fromJson<MyListsResponse>(it, MyListsResponse::class.java)
        mylistsViewModel.setSelectedList(mylists)
    }
    
  4. DetailFragment获取父ViewModel并观察数据

    class DetailFragment : Fragment() {
        // 通过父Fragment作用域获取ViewModel
        private val parentViewModel: MyListsViewModel by viewModels({ requireParentFragment() })
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            // 观察数据更新UI
            parentViewModel.selectedList.observe(viewLifecycleOwner) { data ->
                data?.let {
                    // 用数据渲染UI
                }
            }
        }
    }
    

方案二:直接给子Fragment传递Bundle

如果不想依赖ViewModel共享,可在父Fragment创建子Fragment时,将数据直接传入子Fragment的arguments中。

  1. 父Fragment创建Adapter时传入数据

    class ParentPagerAdapter(
        fragment: Fragment,
        private val listData: MyListsResponse?
    ) : FragmentStateAdapter(fragment) {
        override fun getItemCount(): Int = 2
    
        override fun createFragment(position: Int): Fragment {
            return when(position) {
                0 -> DetailFragment().apply {
                    arguments = Bundle().apply {
                        putString("mylist", Gson().toJson(listData))
                    }
                }
                1 -> SecondFragment()
                else -> throw IllegalArgumentException("Invalid position")
            }
        }
    }
    
    // 父Fragment初始化Adapter
    val mylistsData = ... // 解析后的MyListsResponse实例
    viewPager.adapter = ParentPagerAdapter(this, mylistsData)
    
  2. DetailFragment解析arguments获取数据

    class DetailFragment : Fragment() {
        private var mylists: MyListsResponse? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            arguments?.getString("mylist")?.let { json ->
                mylists = Gson().fromJson(json, MyListsResponse::class.java)
            }
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            mylists?.let {
                // 用数据展示UI
            }
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 09:10:39