NavHost 与 NavController 职责划分:生命周期绑定、导航栈管理、通信通道

在 Navigation 组件中,NavHost 与 NavController 是最核心的两个运行时角色。它们的职责边界决定了架构的分层方式:谁负责 UI 附着?谁负责导航逻辑?谁管理返回栈?谁处理深层链接? 本章围绕模块边界、分层职责、数据流与控制流、风险点与落地步骤,拆解这对核心搭档的协作模型。

模块边界与分层职责

维度NavHostNavController
层级定位UI 层容器导航控制层
生命周期绑定 Activity/Fragment 生命周期独立于 UI,通过 LifecycleOwner 感知
导航栈管理不直接操作返回栈维护 NavBackStackEntry 栈
通信通道作为 NavController 的宿主提供 navigate()、popBackStack()、SavedStateHandle
深层链接处理解析 Intent 并委托给 Controller处理匹配逻辑与栈重建
架构原则:NavHost 是 哑容器,不包含导航决策逻辑;NavController 是 状态中心,所有导航操作最终由它执行。这种分离使得同样一套导航逻辑可复用于不同 UI 框架(Compose / Fragment)。

生命周期绑定机制

NavHost 在其 onCreate / onStart / onResume 等回调中,将自身生命周期状态同步给 NavController。NavController 内部维护一个 LifecycleObserver,用来驱动 NavBackStackEntry 的状态流转。

  • 附着点:NavHost 在 onCreate 中创建 NavController 并调用 setLifecycleOwner(this)。
  • 状态传播:Activity/Fragment 生命周期变化 → NavHost 观察者 → NavController 通知栈中所有 Entry。
  • 安全退出:当宿主生命周期进入 DESTROYED,NavController 自动清空导航栈,防止内存泄漏。

关键代码片段(仅示意边界,非完整实现):

// NavHostFragment 内部
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    navController = NavController(context)
    navController.setLifecycleOwner(this)
    navController.setOnNavigatedListener { /* 回调 */ }
}

导航栈管理职责

NavController 维护一个 Deque<NavBackStackEntry> 作为导航栈。每个 Entry 持有目标目的地 ID、参数、SavedStateHandle。NavHost 不直接操作栈,而是通过 NavController 暴露的方法间接管理:

  1. navigate(destinationId, args) → 压入新 Entry 并触发 Fragment 创建/切换。
  2. popBackStack() → 弹出栈顶 Entry,若栈空则通知宿主 finish。
  3. getBackStackEntry(destinationId) → 允许跨层级获取已有 Entry 的 SavedStateHandle。
风险点:多个 NavHost 实例(如 ViewPager 内嵌)会导致栈混乱。每个 NavController 的栈是独立的,跨容器导航需通过 Parent NavController 代理。

通信通道与数据流

NavController 提供三种通信机制,NavHost 仅负责传递宿主的 ActivityResultRegistry 和 ViewModelStoreOwner:

  • Navigation 参数:通过 NavArgs 在 navigate() 时序列化传递,适合轻量数据。
  • SavedStateHandle:每个 Entry 自带 Bundle 容器,适合跨配置变更保留状态。
  • Shared ViewModel:借助 NavHost 提供的 ViewModelStoreOwner 实现,适合共享业务逻辑。

数据流方向:
源 Fragment → NavArgs/SavedStateHandle → NavController → 目标 Fragment
Shared ViewModel → Activity scope → 所有子 Fragment。

选型权衡

场景推荐方案理由
简单单 Activity 多 FragmentFragmentContainerView + NavHostFragment开箱即用,生命周期自动绑定
Compose 界面NavHost composableCompose 专用实现,无 Fragment 开销
多 Activity 协作每个 Activity 独立 NavController避免栈泄漏,Activity 边界清晰
深层链接唤醒NavController.handleDeepLink()统一解析入口,避免手动栈构建

风险点与应对策略

  • 生命周期滞后:在 NavHost 未完全初始化前调用 navigate() 可能抛出异常。→ 使用 mOnNavigatedListener 或延迟执行。
  • 栈状态不一致:系统重建 Activity 时,NavController 通过 saveState()/restoreState() 恢复,若自定义保存逻辑不完善则数据丢失。→ 确保 SavedStateHandle 中的关键数据可序列化。
  • 通信通道膨胀:过度使用 SavedStateHandle 传递大对象会占用 Bundle 配额。→ 优先使用 ViewModel + Repository 模式。

落地步骤

  1. 在布局中声明 <androidx.fragment.app.FragmentContainerView> 并指定 android:name="androidx.navigation.fragment.NavHostFragment"。
  2. 在 Activity 中获取 NavHostFragment.findNavController(this) 得到 NavController 实例。
  3. 配置 NavGraph 资源文件,绑定起始目的地。
  4. 在需要导航的位置调用 navController.navigate(R.id.action_target)。
  5. 集成深层链接:在 AndroidManifest.xml 添加 intent-filter,并在 Activity 的 onCreate 中调用 navController.handleDeepLink(intent)。

验收标准

  • 生命周期一致性:旋转屏幕后返回栈顺序不变,当前 Fragment 状态保留。
  • 导航栈完整性:连续 navigate 后按返回键能逐级回退,直至退出 Activity。
  • 通信可靠性:通过 SavedStateHandle 传递的数据在配置变更后仍然可用。
  • 深层链接正确性:外部 URL 或 Intent 能直接跳转到目标目的地,且返回栈按预期重建。
NavHost 与 NavController 职责划分架构 UI 容器层 (NavHost) 导航控制层 (NavController) 生命周期 & 通信通道 NavHostFragment Compose NavHost CustomContainer NavController NavBackStackEntry SavvedStateHandle LifecycleObserver ActivityResultRegistry ViewModelStore 每个 NavController 管理独立栈