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

ViewPager2嵌套Fragment下Navigation传值及跳转崩溃问题求助

解决方案:嵌套Fragment间的结果传递与导航问题处理

针对ViewPager2嵌套Fragment无法使用Navigation组件的FragmentResultAPI、导航跳转报错的问题,给你几个可行的解决思路:

1. 接口回调(最简单直接的方案)

因为RegisterPhotoFragment是BeginningFragment通过ViewPager2创建的父子Fragment关系,直接用接口回调传递图片Uri:

  • 定义回调接口:
    interface OnPhotoSelectedListener {
        fun onPhotoSelected(uri: Uri)
    }
    
  • 在RegisterPhotoFragment中持有接口引用,BottomSheet选图后触发回调:
    class RegisterPhotoFragment : Fragment() {
        private var listener: OnPhotoSelectedListener? = null
    
        override fun onAttach(context: Context) {
            super.onAttach(context)
            listener = parentFragment as? OnPhotoSelectedListener
        }
    
        // BottomSheet返回Uri时调用
        private fun onPhotoUriReceived(uri: Uri) {
            listener?.onPhotoSelected(uri)
        }
    
        override fun onDetach() {
            super.onDetach()
            listener = null
        }
    }
    
  • 在BeginningFragment中实现接口,拿到Uri后传递给RegisterPhotoFragment:
    class BeginningFragment : Fragment(), OnPhotoSelectedListener {
        override fun onPhotoSelected(uri: Uri) {
            // 通过ViewPager2的adapter获取目标Fragment实例
            val targetFragment = viewPagerAdapter.instantiateItem(viewPager, 对应页面位置) as RegisterPhotoFragment
            targetFragment.updatePhoto(uri)
        }
    }
    

2. 使用Activity级别的SharedViewModel

利用ViewModel的生命周期特性,让RegisterPhotoFragment和BottomSheet共享Activity级别的ViewModel传递数据:

  • 创建共享ViewModel:
    class PhotoSharedViewModel : ViewModel() {
        val photoUriLiveData = MutableLiveData<Uri?>()
    }
    
  • 在RegisterPhotoFragment中监听LiveData:
    class RegisterPhotoFragment : Fragment() {
        private val sharedViewModel: PhotoSharedViewModel by activityViewModels()
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            sharedViewModel.photoUriLiveData.observe(viewLifecycleOwner) { uri ->
                uri?.let {
                    // 处理图片Uri
                    sharedViewModel.photoUriLiveData.value = null // 重置避免重复接收
                }
            }
        }
    }
    
  • 在BottomSheet中设置LiveData值:
    class CameraOrGalleryBottomSheetDialogFragment : BottomSheetDialogFragment() {
        private val sharedViewModel: PhotoSharedViewModel by activityViewModels()
    
        private fun onSelectPhoto(uri: Uri) {
            sharedViewModel.photoUriLiveData.value = uri
            dismiss()
        }
    }
    

3. 正确配置嵌套导航(符合Navigation组件规范)

如果想继续用FragmentResultAPI,给ViewPager2中的Fragment配置子NavHost,让RegisterPhotoFragment成为子导航起点:

  • 第一步:创建子导航图(如nav_register_photo.xml),设置起始目的地并添加跳转action:
    <navigation xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/nav_register_photo"
        app:startDestination="@id/registerPhotoFragment">
    
        <fragment
            android:id="@+id/registerPhotoFragment"
            android:name="mypackage.presentation.ui.beginning.RegisterPhotoFragment">
            <action
                android:id="@+id/action_registerPhotoFragment_to_cameraOrGalleryBottomSheetDialog"
                app:destination="@id/cameraOrGalleryBottomSheetDialogFragment"/>
        </fragment>
    
        <dialog
            android:id="@+id/cameraOrGalleryBottomSheetDialogFragment"
            android:name="mypackage.presentation.ui.CameraOrGalleryBottomSheetDialogFragment"/>
    </navigation>
    
  • 第二步:在RegisterPhotoFragment布局中添加子NavHost容器:
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/register_photo_nav_host"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:navGraph="@navigation/nav_register_photo"
        app:defaultNavHost="true"/>
    
  • 第三步:在RegisterPhotoFragment中获取子NavController并设置结果监听:
    class RegisterPhotoFragment : Fragment() {
        private lateinit var navController: NavController
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            val navHostFragment = childFragmentManager.findFragmentById(R.id.register_photo_nav_host) as NavHostFragment
            navController = navHostFragment.navController
            
            // 监听FragmentResult
            setFragmentResultListener("photo_request_key") { _, bundle ->
                val uri = bundle.getParcelable<Uri>("photo_uri")
                uri?.let { /* 处理图片Uri */ }
            }
        }
    
        // 点击按钮跳转BottomSheet
        private fun openBottomSheet() {
            navController.navigate(R.id.action_registerPhotoFragment_to_cameraOrGalleryBottomSheetDialog)
        }
    }
    
  • 第四步:在BottomSheet中返回结果:
    class CameraOrGalleryBottomSheetDialogFragment : BottomSheetDialogFragment() {
        private fun sendPhotoUri(uri: Uri) {
            setFragmentResult("photo_request_key", bundleOf("photo_uri" to uri))
            dismiss()
        }
    }
    

此方案让RegisterPhotoFragment作为子导航的当前目的地,跳转时使用子NavController,不会再出现找不到action的错误,同时能正常接收FragmentResult。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:55:17