当前位置: 首页 > news >正文

Jetpack Navigation 实战:Fragment 和 Activity 的交互与导航

在 Android 开发中,使用 Jetpack Navigation 组件可以方便地管理 Fragment 和 Activity 之间的导航。以下是如何使用 Jetpack Navigation 实现 Fragment 之间、Activity 之间以及 Activity 与 Fragment 之间跳转的实战示例。
1. 添加依赖
首先,在 build.gradle 文件中添加 Navigation 组件的依赖:

dependencies {
    implementation "androidx.navigation:navigation-fragment-ktx:2.5.3"
    implementation "androidx.navigation:navigation-ui-ktx:2.5.3"
}

2. 创建导航图
res/navigation 目录下创建一个导航图文件(例如 nav_graph.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"
    app:startDestination="@id/fragmentA">

    <!-- Fragment 之间的导航 -->
    <fragment
        android:id="@+id/fragmentA"
        android:name="com.example.FragmentA"
        tools:layout="@layout/fragment_a">
        <action
            android:id="@+id/action_fragmentA_to_fragmentB"
            app:destination="@id/fragmentB" />
    </fragment>

    <fragment
        android:id="@+id/fragmentB"
        android:name="com.example.FragmentB"
        tools:layout="@layout/fragment_b">
        <action
            android:id="@+id/action_fragmentB_to_fragmentA"
            app:destination="@id/fragmentA" />
    </fragment>

    <!-- Activity 之间的导航 -->
    <activity
        android:id="@+id/activityB"
        android:name="com.example.ActivityB"
        tools:layout="@layout/activity_b" />

    <!-- Activity 与 Fragment 之间的导航 -->
    <fragment
        android:id="@+id/fragmentC"
        android:name="com.example.FragmentC"
        tools:layout="@layout/fragment_c">
        <action
            android:id="@+id/action_fragmentC_to_activityB"
            app:destination="@id/activityB" />
    </fragment>

</navigation>

3. 在 Activity 中设置 NavController
在你的主 Activity 中,设置 NavController 并将其与 NavHostFragment 绑定:

class MainActivity : AppCompatActivity() {

    private lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        navController = navHostFragment.navController

        // 设置 NavigationUI 与 BottomNavigationView 或 NavigationView 的绑定(可选)
        setupNavigationUI()
    }

    private fun setupNavigationUI() {
        // 如果你有 BottomNavigationView 或 NavigationView,可以在这里绑定
        val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav_view)
        bottomNavigationView?.setupWithNavController(navController)
    }
}

4. Fragment 之间的跳转
FragmentA 中,使用 NavController 跳转到 FragmentB

class FragmentA : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_a, container, false)

        view.findViewById<Button>(R.id.button).setOnClickListener {
            findNavController().navigate(R.id.action_fragmentA_to_fragmentB)
        }

        return view
    }
}

5. Activity 之间的跳转
FragmentC 中,使用 NavController 跳转到 ActivityB

class FragmentC : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_c, container, false)

        view.findViewById<Button>(R.id.button).setOnClickListener {
            findNavController().navigate(R.id.action_fragmentC_to_activityB)
        }

        return view
    }
}

在 ActivityB 中,你可以通过 Intent 启动其他 Activity 或返回上一个 Activity。

6. Activity 与 Fragment 之间的跳转
如果你想从 ActivityB 跳转回 FragmentC,可以在 ActivityB 中使用 NavController

class ActivityB : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_b)

        findViewById<Button>(R.id.button).setOnClickListener {
            val navController = findNavController(R.id.nav_host_fragment)
            navController.navigate(R.id.action_activityB_to_fragmentC)
        }
    }
}

7. 处理返回栈
在导航图中,你可以使用 popUpTopopUpToInclusive 属性来控制返回栈的行为。例如:

<action
    android:id="@+id/action_fragmentA_to_fragmentB"
    app:destination="@id/fragmentB"
    app:popUpTo="@id/fragmentA"
    app:popUpToInclusive="true" />

这将在跳转到 FragmentB 时清除返回栈中的所有 FragmentA 实例。

8. 处理 Deep Links
你还可以使用 Navigation 组件处理 Deep Links。在导航图中为 Fragment 或 Activity 添加 deepLink

<fragment
    android:id="@+id/fragmentC"
    android:name="com.example.FragmentC"
    tools:layout="@layout/fragment_c">
    <deepLink app:uri="example.com/fragmentC" />
</fragment>

然后在 AndroidManifest.xml 中为 Activity 添加 nav-graph

<activity android:name=".MainActivity">
    <nav-graph android:value="@navigation/nav_graph" />
</activity>

9.在导航图中定义参数
在 Jetpack Navigation 中,传递参数非常简单。我们可以在导航图中定义参数,并在跳转时通过 Bundle 传递数据。以下是一个简单的实战示例,展示如何在 Fragment 之间传递参数。

在导航图中定义参数
在 nav_graph.xml 中,为目标 Fragment 定义参数。例如,为 FragmentB 定义一个 String 类型的参数 userName:

<fragment
    android:id="@+id/fragmentB"
    android:name="com.example.FragmentB"
    tools:layout="@layout/fragment_b">

    <!-- 定义参数 -->
    <argument
        android:name="userName"
        app:argType="string" />

    <action
        android:id="@+id/action_fragmentA_to_fragmentB"
        app:destination="@id/fragmentB" />
</fragment>

在 FragmentA 中传递参数
在 FragmentA 中,使用 NavController 跳转到 FragmentB 并传递参数:

class FragmentA : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_a, container, false)

        view.findViewById<Button>(R.id.button).setOnClickListener {
            // 创建 Bundle 并传递参数
            val bundle = Bundle()
            bundle.putString("userName", "JohnDoe")

            // 跳转到 FragmentB 并传递参数
            findNavController().navigate(R.id.action_fragmentA_to_fragmentB, bundle)
        }

        return view
    }
}

在 FragmentB 中接收参数
在 FragmentB 中,通过 arguments 获取传递过来的参数:

class FragmentB : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_b, container, false)

        // 获取传递的参数
        val userName = arguments?.getString("userName")
        if (userName != null) {
            // 使用参数(例如显示在 TextView 中)
            view.findViewById<TextView>(R.id.textView).text = "Hello, $userName!"
        }

        return view
    }
}

使用 Safe Args 插件(推荐)
为了更安全地传递参数,可以使用 Navigation 的 Safe Args 插件。它会在编译时生成类型安全的代码,避免手动处理 Bundle。

添加 Safe Args 依赖
在 build.gradle 文件中添加 Safe Args 插件:

plugins {
    id "androidx.navigation.safeargs.kotlin"
}

在导航图中定义参数(同上)
在 FragmentA 中使用 Safe Args 传递参数

view.findViewById<Button>(R.id.button).setOnClickListener {
    // 使用 Safe Args 传递参数
    val action = FragmentADirections.actionFragmentAToFragmentB("JohnDoe")
    findNavController().navigate(action)
}

在 FragmentB 中使用 Safe Args 接收参数

class FragmentB : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_b, container, false)

        // 使用 Safe Args 获取参数
        val args by navArgs<FragmentBArgs>()
        val userName = args.userName

        // 使用参数
        view.findViewById<TextView>(R.id.textView).text = "Hello, $userName!"

        return view
    }
}

总结
通过 Jetpack Navigation 组件,你可以轻松实现 Fragment 之间、Activity 之间以及 Activity 与 Fragment 之间的跳转。导航图提供了清晰的导航结构,并且可以方便地管理返回栈和 Deep Links。

通过以上步骤,你可以轻松地在 Fragment 之间传递参数:

普通方式:使用 Bundle 手动传递参数。

Safe Args:使用 Navigation 的 Safe Args 插件,实现类型安全的参数传递。

如果你需要传递复杂对象(如自定义类),可以结合 ParcelableSerializable 来实现。希望这个补充内容对你有帮助!

相关文章:

  • Android Glide 缓存模块源码深度解析
  • SpringBoot缓存抽象:@Cacheable与缓存管理器配置
  • Vite项目中vite.config.js中为什么只能使用process.env,无法使用import.meta.env?
  • SpringCloud Alibaba——入门简介
  • 利用ArcGIS Pro进行爆炸波及建筑分析:详细步骤与技巧
  • 鸿蒙模拟器运行NDK项目失败 9568347
  • 【ai塔罗牌-生命之树】【azure openai】【python】交互塔罗牌demo
  • 【大模型系列】llama.cpp本地运行大模型
  • [排序算法]直接插入排序
  • 数据采集技术之python网络爬虫(中国天气网的爬取)
  • 动态规划(1. 第 N 个泰波那契数)
  • 【prompt实战】知乎问题解答专家
  • Mac java全栈开发环境配置
  • 【Linux】在VMWare中安装Ubuntu操作系统(2025最新_Ubuntu 24.04.2)#VMware安装Ubuntu实战分享#
  • SSL 配置
  • Token登录授权、续期和主动终止的方案(Redis+Token(非jwtToken))
  • 用小程序制作好看的手机壁纸或者海报:Canva可画
  • 【面试题集合】
  • 【3-12 toupper(ch) tolower(ch) 和ASCII码 和全排列】
  • Android Retrofit 框架适配器模块深入源码分析(五)
  • 男子恶意遗弃幼子获刑,最高法发布涉未成年人家庭保护典型案例
  • 广西北部湾国际港务集团副总经理潘料庭接受审查调查
  • 菲律宾中期选举初步结果出炉,杜特尔特家族多人赢得地方选举
  • 中国巴西关于乌克兰危机的联合声明
  • 工人日报:“鼠标手”被纳入职业病,劳动保障网越织越密
  • 香港暂停进口美国北达科他州一地区禽肉及禽类产品