Android 学习之 Navigation导航

1. Navigation 介绍

Navigation 组件 是 Android Jetpack 的一部分,用于简化应用内导航逻辑,支持 Fragment、Activity 和 Compose 之间的跳转。核心优势:

  • 单 Activity 架构:减少 Activity 冗余,通过 Fragment 或 Compose 实现界面切换。
  • 可视化导航图:通过 XML 或代码声明页面跳转关系。
  • 统一返回栈管理:自动处理返回按钮和手势导航。
  • 类型安全的参数传递:通过 Safe Args 插件或 Compose 的 Route 实现。

2. 项目中导入 Navigation 插件

传统 View 项目 (XML + Fragment)

build.gradle (Module) 中添加依赖:

dependencies {def nav_version = "2.7.7"implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"implementation "androidx.navigation:navigation-ui-ktx:$nav_version"// Safe Args 插件(可选)classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
}

Compose 项目

build.gradle (Module) 中添加:

dependencies {def nav_version = "2.7.7"implementation "androidx.navigation:navigation-compose:$nav_version"
}

在导入时要尤其注意导入的是 navigation-fragment 还是 navigation-compose 两者的使用有很大区别


3. 实现 Navigation 导航(XML + Fragment)

步骤 1:创建导航图

res/navigation 目录下新建 nav_graph.xml

<navigation xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/nav_graph"app:startDestination="@id/homeFragment"><fragmentandroid:id="@+id/homeFragment"android:name="com.example.HomeFragment"android:label="Home"><actionandroid:id="@+id/action_to_detail"app:destination="@id/detailFragment" /></fragment><fragmentandroid:id="@+id/detailFragment"android:name="com.example.DetailFragment"android:label="Detail" />
</navigation>

其中的action属于显式定义动作,如果是跳转页面的话可以不显式定义,但如果使用androidx.navigation:safe-args插件必须定义动作才能生成参数类。

步骤 2:配置 NavHost

在 Activity 的布局中添加 NavHostFragment

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

步骤 3:执行导航操作

在 Fragment 中通过 NavController 跳转:

// HomeFragment.kt
button.setOnClickListener {findNavController().navigate(R.id.action_to_detail)
}

参数传递(Safe Args)

  1. nav_graph.xml 中定义参数:
<fragment android:id="@+id/detailFragment"><argumentandroid:name="userId"app:argType="string" />
</fragment>
  1. 通过 Safe Args 传递参数:
val action = HomeFragmentDirections.actionToDetail("user123")
findNavController().navigate(action)

4. 基于 Compose 的 Navigation 导航

步骤 1:定义路由

在 Compose 中通过字符串定义路由:

object Routes {const val HOME = "home"const val DETAIL = "detail/{userId}"
}

步骤 2:配置 NavController

MainActivity 中初始化导航控制器:

val navController = rememberNavController()
NavHost(navController = navController, startDestination = Routes.HOME) {composable(Routes.HOME) {HomeScreen(onNavigateToDetail = { userId ->navController.navigate("detail/$userId")})}composable(Routes.DETAIL) { backStackEntry ->val userId = backStackEntry.arguments?.getString("userId")DetailScreen(userId = userId)}
}

步骤 3:触发导航

HomeScreen 中点击按钮跳转:

Button(onClick = { onNavigateToDetail("user123") }) {Text("Go to Detail")
}

5. 总结

  • 传统 XML 方式:适合已有 Fragment 项目,通过可视化导航图管理跳转逻辑。
  • Compose 方式:声明式 API,更适合现代化 Compose 项目,路由管理更灵活。
  • 核心优点:统一导航逻辑、类型安全、简化返回栈管理。

推荐场景

  • 新项目优先使用 Compose Navigation。
  • 旧项目逐步迁移时,可混合使用 XML 和 Compose 导航。

6. 拓展

1. 多模块导航

核心场景
  • 大型项目中按功能拆分模块(如登录模块、支付模块、个人中心模块)。
  • 模块间解耦,允许独立开发和测试。
实现方案
步骤 1:创建子模块
  1. 新建模块

    • 在 Android Studio 中右键项目 → New → Module → 选择 Phone & Tablet ModuleAndroid Library
    • 命名模块(如 feature-auth),包名建议为 com.example.feature.auth
  2. 模块结构

    project-root/|- app/                  // 主模块|- feature-auth/         // 子模块|- src/main/|- res/navigation/auth_nav_graph.xml  // 子模块导航图
    
步骤 2:子模块定义导航图

在子模块中创建独立的导航图:

<!-- feature-auth/res/navigation/auth_nav_graph.xml -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/auth_nav_graph"app:startDestination="@id/loginFragment"><fragmentandroid:id="@+id/loginFragment"android:name="com.example.feature.auth.LoginFragment"><actionandroid:id="@+id/action_to_register"app:destination="@id/registerFragment" /></fragment><fragment android:id="@+id/registerFragment" ... />
</navigation>
步骤 3:主模块集成子模块
  1. 添加依赖
    在主模块的 build.gradle 中引入子模块:

    dependencies {implementation project(":feature-auth")
    }
    
  2. 合并导航图
    在主导航图中通过 <include> 引入子模块导航图:

    <!-- app/res/navigation/main_nav_graph.xml -->
    <navigation ...><fragment android:id="@+id/homeFragment"><actionandroid:id="@+id/action_to_auth"app:destination="@id/auth_nav_graph" /></fragment><include app:graph="@navigation/auth_nav_graph" />  <!-- 关键 -->
    </navigation>
    
  3. 跨模块跳转
    直接使用子模块的 Action ID 或 Destination ID:

    // 从主模块跳转到子模块的登录页
    findNavController().navigate(R.id.action_to_auth)
    
参数传递
  1. 子模块定义参数

    <!-- auth_nav_graph.xml -->
    <fragment android:id="@+id/registerFragment"><argument android:name="email" app:argType="string" />
    </fragment>
    
  2. 主模块传递参数

    // 使用生成的 Directions 类(需主模块依赖子模块的 Safe Args)
    val directions = LoginFragmentDirections.actionToRegister(email = "user@example.com")
    findNavController().navigate(directions)
    
注意事项
  • 资源冲突:子模块资源需添加前缀(如 auth_),避免与主模块重复。
  • 依赖版本一致:主模块和子模块的 Navigation 版本必须相同。
  • ProGuard 规则:保留子模块生成的导航类。

2. 深层链接(DeepLink)

核心场景
  • 从外部链接直接跳转到应用内指定页面(如邮件中的订单详情链接)。
  • Web 页面与应用页面对接。
实现方案
XML + Fragment 方式
  1. 在导航图中定义 DeepLink

    <fragment android:id="@+id/detailFragment"><deepLink app:uri="example://app/detail/{id}" />  <!-- 定义 URI 模板 -->
    </fragment>
    
  2. 配置 AndroidManifest
    <activity> 标签内添加 Intent Filter:

    <activity ...><intent-filter><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.BROWSABLE" /><!-- 协议和域名 --><dataandroid:scheme="example"android:host="app"android:pathPrefix="/detail" /></intent-filter>
    </activity>
    
  3. 处理 DeepLink 参数

    class DetailFragment : Fragment() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)arguments?.let {val id = it.getString("id")  // 从 URI 中提取参数}}
    }
    
Compose 方式
  1. 定义 DeepLink 路由

    composable(route = "detail/{id}",deepLinks = listOf(navDeepLink { uriPattern = "example://app/detail/{id}" })
    ) { backStackEntry ->val id = backStackEntry.arguments?.getString("id")DetailScreen(id = id)
    }
    
  2. 触发 DeepLink

    // 通过 URI 跳转
    val request = NavDeepLinkRequest.Builder.fromUri("example://app/detail/123".toUri()).build()
    navController.navigate(request)
    
测试 DeepLink

使用 ADB 命令模拟 DeepLink:

adb shell am start -d "example://app/detail/123" com.example.app
注意事项
  • 路径匹配:URI 的 pathPattern 需与导航图中定义一致。
  • 安全性:验证外部传入参数,避免恶意数据注入。
  • 多模块 DeepLink:子模块的 DeepLink 需在主模块的 AndroidManifest 中声明。

总结

  • 多模块导航:通过模块拆分和 <include> 标签整合导航图,实现功能解耦和代码复用。
  • 深层链接:通过 URI 映射应用内页面,提升用户体验和外部系统集成能力。

推荐实践

  • 在电商应用中,订单模块可独立为子模块,通过 DeepLink 实现从推送通知直接跳转订单详情。
  • 社交应用中将个人主页模块化,通过 feature-profile 子模块管理,支持外部链接直达用户主页。

GitHub 多模块示例 | DeepLink 官方指南

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/76059.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker Compose 部署Nginx反向代理 tomcat

Nginx 、Tomcat (默认端口8080)》》compose services:nginx:image: nginx:latestcontainer_name: nginxrestart: alwaysports:- 80:80- 8080:8080volumes:# 文件夹会自动创建&#xff0c;但nginx.conf是文件&#xff0c;需要提前创建&#xff0c;否则 会自动创建nginx.conf文件…

数据库7(数据定义语句,视图,索引)

1.数据定义语句 SQL数据定义语言&#xff08;DDL&#xff09;用于定义和管理数据库结构&#xff0c;包括创建、修改和删除 数据库对象。常见的DDL语句包括CREATE、DROP和ALTER。 它的操作的是对象&#xff0c;区分操作数据的语句&#xff1a;INSERT,DELETE,UPDATE 示例&#x…

QML面试笔记--UI设计篇02布局控件

1. QML 中常用的布局控件 1.1. Row1.2. Column1.3. Grid1.4. RowLayout1.5. ColumnLayout1.6. GridLayout1.7. 总结 1. QML 中常用的布局控件 1.1. Row 背景知识&#xff1a;Row 布局用于将子元素水平排列&#xff0c;适合简单的线性布局&#xff0c;如工具栏按钮或表单输入…

Compose组件转换XML布局1.0

文章目录 学习JetPack Compose资源前言&#xff1a;预览界面的实现Compose组件的布局管理一、Row和Colum组件&#xff08;LinearLayout&#xff09;LinearLayout&#xff08;垂直方向 → Column&#xff09;LinearLayout&#xff08;水平方向 → Row&#xff09; 二、相对布局 …

从零构建大语言模型全栈开发指南:第五部分:行业应用与前沿探索-5.2.1模型偏见与安全对齐(Red Teaming实践)

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 大语言模型全栈开发指南:伦理与未来趋势 - 第五部分:行业应用与前沿探索5.2.1 模型偏见与安全对齐(Red Teaming实践)一、模型偏见的来源与影响1. 偏见的定义与分类2. 偏见的实际影响案例二、安全对齐…

java基础 迭代Iterable接口以及迭代器Iterator

Itera迭代 Iterable < T>迭代接口(1) Iterator iterator()(2) forEach(Consumer<? super T> action)forEach结合Consumer常见场景forEach使用注意细节 (3)Spliterator spliterator() Iterator< T>迭代器接口如何“接收” Iterator<T>核心方法迭代器的…

PyTorch构建自定义模型

PyTorch 提供了灵活的方式来构建自定义神经网络模型。下面我将详细介绍从基础到高级的自定义模型构建方法&#xff0c;包含实际代码示例和最佳实践。 一、基础模型构建 1. 继承 nn.Module 基类 所有自定义模型都应该继承 torch.nn.Module 类&#xff0c;并实现两个基本方法&…

AI智算-K8s如何利用GPFS分布式并行文件存储加速训练or推理

文章目录 GPFS简介核心特性存储环境介绍存储软件版本客户端存储RoCEGPFS 管理(GUI)1. 创建 CSI 用户2. 检查GUI与k8s通信文件系统配置1. 开启配额2. 启用filesetdf文件系统3. 验证文件系统配置4. 启用自动inode扩展存储集群配置1. 启用对根文件集(root fileset)配额2. igno…

gbase8s之逻辑导出导入脚本(完美版本)

该脚本dbexport.sh用于快速导出库和导入库&#xff08;使用多并发unload&#xff0c;和多并发dbload的方式&#xff09; #!/bin/sh #脚本功能&#xff1a;将数据导出成文本&#xff0c;迁移至其他实例 #最后更新时间&#xff1a;2023-12-19 #使用方法&#xff1a; #1.执行该脚…

springMVC-拦截器详解

拦截器 概述 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。 过滤器与拦截器的区别&#xff1a;拦截器是AOP思想的具体应用。 过滤器 servlet规范中的一部分&#xff0c;任何ja…

网络安全应急响应-系统排查

在网络安全应急响应中&#xff0c;系统排查是快速识别潜在威胁的关键步骤。以下是针对Windows和Linux系统的系统基本信息排查指南&#xff0c;涵盖常用命令及注意事项&#xff1a; 一、Windows系统排查 1. 系统信息工具&#xff08;msinfo32.exe&#xff09; 命令执行&#x…

基于YOLO的半自动化标注方法:提升铁路视频缺陷检测效率

论文地址:https://arxiv.org/pdf/2504.01010 1. 论文结构概述 本文提出了一种半自动化标注方法,旨在解决铁路缺陷检测中大规模图像/视频数据集标注成本高、耗时长的问题。论文结构清晰,分为以下核心部分: ​引言(Introduction)​ 强调传统手动标注的痛点(耗时、易错、…

Linux驱动开发:SPI驱动开发原理

前言 本文章是根据韦东山老师的教学视频整理的学习笔记https://video.100ask.net/page/1712503 SPI 通信协议采用同步全双工传输机制&#xff0c;拓扑架构支持一主多从连接模式&#xff0c;这种模式在实际应用场景中颇为高效。其有效传输距离大致为 10m &#xff0c;传输速率…

Android Hilt 教程

Android Hilt 教程 —— 一看就懂&#xff0c;一学就会 1. 什么是 Hilt&#xff1f;为什么要用 Hilt&#xff1f; Hilt 是 Android 官方推荐的 依赖注入&#xff08;DI&#xff09;框架&#xff0c;基于 Dagger 开发&#xff0c;能够大大简化依赖注入的使用。 为什么要用 Hi…

【算法手记11】NC41 最长无重复子数组 NC379 重排字符串

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:刷题 ⚙️操作环境:牛客网 目录 一.NC41 最长无重复子数组 题目详情: 题目思路: 解题代码: 二.NC379 重排字符串 题目详情: 题目思路: 解题代码: 结语 一.NC41 最长无重复子数组 牛客网题目链接(点击即可跳转):NC41 最长…

C语言:字符串处理函数strstr分析

在 C 语言中&#xff0c;strstr 函数用于查找一个字符串中是否存在另一个字符串。它的主要功能是搜索指定的子字符串&#xff0c;并返回该子字符串在目标字符串中第一次出现的位置的指针。如果没有找到子字符串&#xff0c;则返回 NULL。 详细说明&#xff1a; 头文件&#xf…

在windows下安装spark

在windows下安装spark完成 安装过程&#xff1a;

MongoDB常见面试题总结(上)

MongoDB 基础 MongoDB 是什么&#xff1f; MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统&#xff0c;由 C 编写的。MongoDB 提供了 面向文档 的存储方式&#xff0c;操作起来比较简单和容易&#xff0c;支持“无模式”的数据建模&#xff0c;可以存储比较复杂…

【Java设计模式】第2章 UML急速入门

2-1 本章导航 UML类图与时序图入门 UML定义 统一建模语言(Unified Modeling Language):第三代非专利建模语言。特点:开放方法,支持可视化构建面向对象系统,涵盖模型、流程、代码等。UML分类(2.2版本) 结构式图形:系统静态建模(类图、对象图、包图)。行为式图形:事…

【4】搭建k8s集群系列(二进制部署)之安装master节点组件(kube-apiserver)

一、下载k8s二进制文件 下载地址&#xff1a; https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG -1.20.md 注&#xff1a;打开链接你会发现里面有很多包&#xff0c;下载一个 server 包就够了&#xff0c;包含了 Master 和 Worker Node 二进制文件。…