Android Navigation的使用说明

8.1.1 传统导航方式的痛点,以及Navigation的优势

传统导航方式的问题

kotlin 复制代码
// 传统方式 - 使用 FragmentTransaction 手动管理导航
class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // 手动添加 Fragment
        supportFragmentManager.beginTransaction()
            .add(R.id.fragmentContainer, HomeFragment())
            .commit()
    }
    
    fun navigateToUserDetail(userId: String) {
        // 手动管理 Fragment 切换
        val fragment = UserDetailFragment()
        val args = Bundle()
        args.putString("userId", userId)
        fragment.arguments = args
        
        supportFragmentManager.beginTransaction()
            .replace(R.id.fragmentContainer, fragment)
            .addToBackStack("UserDetail")
            .commit()
    }
    
    fun navigateToSettings() {
        // 手动管理 Fragment 切换
        supportFragmentManager.beginTransaction()
            .replace(R.id.fragmentContainer, SettingsFragment())
            .addToBackStack("Settings")
            .commit()
    }
    
    override fun onBackPressed() {
        // 手动处理返回键
        if (supportFragmentManager.backStackEntryCount > 0) {
            supportFragmentManager.popBackStack()
        } else {
            super.onBackPressed()
        }
    }
}

传统方式的痛点

痛点 说明 影响
代码分散 导航逻辑分散在各个地方 难以维护和理解
返回堆栈管理 需要手动管理返回堆栈 容易出现导航错误
参数传递 需要手动构建 Bundle 类型不安全
测试困难 导航逻辑与业务逻辑耦合 难以单元测试
深层链接 实现复杂 需要大量代码
kotlin 复制代码
// 使用 Navigation 组件 - 简化的导航
class MainActivity : AppCompatActivity() {
    
    private lateinit var navController: NavController
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // 获取 NavController
        navController = findNavController(R.id.navHostFragment)
        
        // 设置导航图
        navController.setGraph(R.navigation.nav_graph)
    }
    
    fun navigateToUserDetail(userId: String) {
        // 类型安全的导航
        navController.navigate(
            R.id.action_homeFragment_to_userDetailFragment,
            bundleOf("userId" to userId)
        )
    }
    
    fun navigateToSettings() {
        // 简单的导航
        navController.navigate(R.id.action_homeFragment_to_settingsFragment)
    }
}

Navigation 组件的优势

优势 说明
可视化导航 可视化的导航图,直观展示应用导航结构
类型安全 使用 Safe Args,类型安全的参数传递
自动管理返回堆栈 自动管理 Fragment 的返回堆栈
深层链接支持** 轻松实现深层链接
动画支持 内置转场动画支持
易于测试 导航逻辑与业务逻辑分离

8.2.1 导航图的基本结构

Navigation Graph XML 结构

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<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_graph"
    app:startDestination="@id/homeFragment">

    <!-- 目的地1:首页 -->
    <fragment
        android:id="@+id/homeFragment"
        android:name="com.example.app.ui.home.HomeFragment"
        android:label="Home"
        tools:layout="@layout/fragment_home">
        
        <!-- 动作:导航到用户详情页 -->
        <action
            android:id="@+id/action_homeFragment_to_userDetailFragment"
            app:destination="@id/userDetailFragment" />
        
        <!-- 动作:导航到设置页 -->
        <action
            android:id="@+id/action_homeFragment_to_settingsFragment"
            app:destination="@id/settingsFragment" />
    </fragment>

    <!-- 目的地2:用户详情页 -->
    <fragment
        android:id="@+id/userDetailFragment"
        android:name="com.example.app.ui.user.UserDetailFragment"
        android:label="User Detail"
        tools:layout="@layout/fragment_user_detail">
        
        <!-- 参数:用户 ID -->
        <argument
            android:name="userId"
            android:defaultValue=""
            app:argType="string"
            app:nullable="true" />
        
        <!-- 动作:返回首页 -->
        <action
            android:id="@+id/action_userDetailFragment_to_homeFragment"
            app:destination="@id/homeFragment"
            app:popUpTo="@id/homeFragment"
            app:popUpToInclusive="true" />
    </fragment>

    <!-- 目的地3:设置页 -->
    <fragment
        android:id="@+id/settingsFragment"
        android:name="com.example.app.ui.settings.SettingsFragment"
        android:label="Settings"
        tools:layout="@layout/fragment_settings">
        
        <!-- 动作:返回首页 -->
        <action
            android:id="@+id/action_settingsFragment_to_homeFragment"
            app:destination="@id/homeFragment"
            app:popUpTo="@id/homeFragment"
            app:popUpToInclusive="true" />
    </fragment>

</navigation>

8.2.2 目的地类型

Navigation 支持的目的地类型

类型 说明 使用场景
Fragment Fragment 目的地 最常用的目的地类型
Activity Activity 目的地 跨 Activity 导航
Dialog Dialog 目的地 显示对话框
NavGraph 嵌套导航图 复杂的导航结构

不同目的地的示例

xml 复制代码
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/homeFragment">

    <!-- Fragment 目的地 -->
    <fragment
        android:id="@+id/homeFragment"
        android:name="com.example.app.ui.home.HomeFragment"
        android:label="Home" />

    <!-- Activity 目的地 -->
    <activity
        android:id="@+id/mainActivity"
        android:name="com.example.app.MainActivity"
        android:label="Main Activity" />

    <!-- Dialog 目的地 -->
    <dialog
        android:id="@+id/dialogFragment"
        android:name="com.example.app.ui.dialog.MyDialogFragment"
        android:label="Dialog" />

    <!-- 嵌套导航图 -->
    <include app:graph="@navigation/nested_graph" />

</navigation>

8.2.3 动作(Action)的配置

动作的属性

xml 复制代码
<fragment
    android:id="@+id/homeFragment"
    android:name="com.example.app.ui.home.HomeFragment"
    android:label="Home">
    
    <!-- 基本动作 -->
    <action
        android:id="@+id/action_home_to_detail"
        app:destination="@id/detailFragment" />
    
    <!-- 带返回堆栈管理的动作 -->
    <action
        android:id="@+id/action_home_to_profile"
        app:destination="@id/profileFragment"
        app:popUpTo="@id/homeFragment"
        app:popUpToInclusive="true" />
    
    <!-- 带转场动画的动作 -->
    <action
        android:id="@+id/action_home_to_settings"
        app:destination="@id/settingsFragment"
        app:enterAnim="@anim/slide_in_right"
        app:exitAnim="@anim/slide_out_left"
        app:popEnterAnim="@anim/slide_in_left"
        app:popExitAnim="@anim/slide_out_right" />
    
    <!-- 单实例导航 -->
    <action
        android:id="@+id/action_home_to_login"
        app:destination="@id/loginFragment"
        app:launchSingleTop="true" />
</fragment>

相关推荐
andyweike4 小时前
Android Automotive
android
又见情义5 小时前
记一次 RK3568 Android 13 蓝牙反复重启问题的排查与修复
android
hai_android5 小时前
Kotlin Flow combine 源码剖析:一个 Channel 如何优雅合并多条流
android·java·kotlin
敲代码的瓦龙7 小时前
Jetpack?ViewModel!!!
android·开发语言·kotlin·android-studio
Godikov7 小时前
Android 工控终端实战:从秒级卡顿到毫秒响应,SQLite/LitePal 性能优化全记录
android
星间都市山脉9 小时前
Android16 SystemService.onBootPhase 调用时机
android·java·linux·windows·ubuntu
swithun9 小时前
不用 WebView,我用 Kotlin + Compose Multiplatform 重写 Mermaid,并做了 2048 组对拍
android·开源·kotlin
AI吃大瓜9 小时前
人脸检测和行人检测4:Android实现YOLOv8 YOLO11 YOLO26人脸检测和人体检测(含源码,可实时检测)
android·yolo·人脸检测·人体检测·行人检测·yolo26
与海boy10 小时前
Prompt模版
android·prompt
FlightYe10 小时前
音视频修炼之编码器(一):AVC、HEVC编码器内部
android·linux·c++·音视频