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

ViewPager中Fragment调用findNavController抛异常,仅配置变更后触发

问题:配置变更后调用findNavController抛出IllegalArgumentException
  • 触发场景:使用FragmentStateAdapter为ViewPager创建的Fragment,在onViewCreated()方法中调用findNavController(requireActivity(), R.id.mainNavHostFragment)时抛出异常
  • 异常信息:IllegalArgumentException: ID does not reference a View inside this Activity
  • 触发条件:仅在设备配置变更(如旋转屏幕)后返回应用时出现
  • 已知前提:NavHostFragment确实存在于该Fragment所属的Activity中,引用的ID完全正确

相关代码

activity_main.xml中的NavHost配置

<fragment
        android:id="@+id/mainNavHostFragment"
        class="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="?attr/actionBarSize"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

Fragment的onViewCreated实现

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    navController = try {
        findNavController(view)
    } catch (e: IllegalStateException) {
        findNavController(requireActivity(), R.id.mainNavHostFragment)
    }
    keyboardManager.registerKeyboardConsumer(this)
}

解决方案

原因分析

配置变更后Activity会重建,ViewPager中的Fragment可能在Activity视图层级完全初始化完成前就执行了onViewCreated(),此时通过Activity查找NavHost的视图ID会失败。另外,findNavController(requireActivity(), id)的调用依赖Activity视图已完全构建,配置变更后的生命周期时序打破了这个前提。

修复方案

  1. 通过FragmentManager获取NavHostFragment实例
    避免直接通过Activity查找视图ID,转而通过FragmentManager获取NavHostFragment实例,再从中获取NavController:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        navController = try {
            findNavController(view)
        } catch (e: IllegalStateException) {
            val navHostFragment = requireActivity().supportFragmentManager.findFragmentById(R.id.mainNavHostFragment) as NavHostFragment
            navHostFragment.navController
        }
        keyboardManager.registerKeyboardConsumer(this)
    }
    
  2. 延迟执行NavController获取逻辑
    利用view.post()将获取操作延迟到主线程消息队列末尾,确保Activity视图已完全初始化:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.post {
            navController = try {
                findNavController(view)
            } catch (e: IllegalStateException) {
                findNavController(requireActivity(), R.id.mainNavHostFragment)
            }
            keyboardManager.registerKeyboardConsumer(this)
        }
    }
    
  3. 优化FragmentStateAdapter的重建逻辑
    确保配置变更后Fragment的标识稳定,避免出现Fragment与Activity视图层级不同步的情况:

    class YourPagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
        override fun getItemCount(): Int = // 替换为你的页面总数
    
        override fun createFragment(position: Int): Fragment = // 替换为对应位置的Fragment创建逻辑
    
        override fun getItemId(position: Int): Long {
            // 返回唯一标识,确保配置变更后Fragment可正确匹配
            return position.toLong()
        }
    
        override fun containsItem(itemId: Long): Boolean {
            return itemId in 0 until getItemCount()
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 08:25:10