目录
  1. 1. 一、NavGraph:声明式导航图
  2. 2. 二、NavHostFragment:导航容器
  3. 3. 三、类型安全的参数传递(Safe Args)
  4. 4. 四、DeepLink 与 BottomNavigation 集成
  5. 5. 五、返回栈高级控制
  6. 6. 面试常考问题
JetPack全家桶(八)之Navigation导航组件

Navigation 是 Jetpack 中专门管理 Fragment 跳转与返回栈的组件。它通过声明式导航图(NavGraph)统一管理目标页面、跳转动画、参数传递,彻底告别手写 FragmentTransaction 的繁琐与易错。

一、NavGraph:声明式导航图

res/navigation/nav_main.xml 中定义所有目标:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_main"
app:startDestination="@id/homeFragment">

<fragment
android:id="@+id/homeFragment"
android:name="com.example.HomeFragment"
android:label="首页"
tools:layout="@layout/fragment_home">
<action
android:id="@+id/action_home_to_detail"
app:destination="@id/detailFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
</fragment>

<fragment
android:id="@+id/detailFragment"
android:name="com.example.DetailFragment"
android:label="详情">
<argument
android:name="articleId"
app:argType="integer"
android:defaultValue="0" />
</fragment>
</navigation>

二、NavHostFragment:导航容器

在 Activity 布局中放置 NavHostFragment:

<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:navGraph="@navigation/nav_main"
app:defaultNavHost="true" />

app:defaultNavHost="true" 确保该 NavHostFragment 拦截系统返回键,自动管理返回栈。

三、类型安全的参数传递(Safe Args)

Safe Args 是 Navigation 的 Gradle 插件,在编译期生成类型安全的导航与参数获取代码:

// 跳转并传递参数(Safe Args 生成 Directions 类)
val action = HomeFragmentDirections.actionHomeToDetail(articleId = 123)
findNavController().navigate(action)

// 目标页面接收参数(Safe Args 生成 Args 类)
class DetailFragment : Fragment() {
private val args: DetailFragmentArgs by navArgs()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val articleId = args.articleId // 类型安全,无需手动 getInt
}
}

DeepLink:通过 NavDeepLinkBuilder 构建 PendingIntent 或直接在 NavGraph 中声明 <deepLink>,实现外部 URL 直达应用内页面。

BottomNavigation 集成

val navController = findNavController(R.id.nav_host_fragment)
bottomNav.setupWithNavController(navController)

NavigationUI 自动处理 tab 选中状态同步与返回栈管理。需确保 menu item 的 id 与 NavGraph 中 fragment 的 id 保持一致。

五、返回栈高级控制

// 跳转到目标并弹出中间所有页面
findNavController().navigate(
HomeFragmentDirections.actionToSettings(),
NavOptions.Builder()
.setPopUpTo(R.id.homeFragment, inclusive = false)
.build()
)

面试常考问题

Q1:Navigation 与手动 FragmentTransaction 对比优势?

Navigation 提供类型安全的 Safe Args、声明式导航图可视化、内置动画支持、自动处理返回栈与 DeepLink、与 BottomNavigation/DrawerLayout 等 UI 组件无缝集成。减少 XML 布局嵌套和大量 FragmentManager 样板代码。

Q2:NavController 的作用域?

每个 NavHostFragment 有独立的 NavController。通过 findNavController() 获取,Ktx 扩展函数自动按 View 向上查找所属的 NavController。Fragment 的 findNavController() 必须在该 Fragment 位于 NavHostFragment 内时调用才有效。

Q3:如何在 ViewModel 级别驱动导航?

推荐通过 LiveData/StateFlow 暴露导航事件(如 SingleLiveEvent),View 层观察后调用 NavController。避免在 ViewModel 中持有 NavController 引用,保持 ViewModel 对导航框架无感知,便于单元测试。

打赏
  • 微信
  • 支付宝

评论