ViewPager中Fragment调用findNavController抛异常,仅配置变更后触发
- 触发场景:使用
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视图已完全构建,配置变更后的生命周期时序打破了这个前提。
修复方案
通过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) }延迟执行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) } }优化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
相关产品推荐
相关产品推荐

