Jetpack学习之Navigation

最近项目中用到了很多Jetpack相关的东西,决定把Jetpack从头到尾撸一遍,先撸了一下Navigation,通过一些简单的代码记录一下比较关键的东西。

Navigation基本介绍

借用Jetpack官方介绍,Navigation是指支持用户导航、进入和退出应用中不同内容片段的交互。Android Jetpack 的Navigation组件可帮助您实现导航,无论是简单的按钮点击,还是应用栏和抽屉式导航栏等更为复杂的模式,该组件均可应对。Navigation组件还通过遵循一套既定原则来确保一致且可预测的用户体验。

简单来说,Jetpack-Navigation组件可以让我们更为方便地管理Fragment的切换,包括参数传递,切换动画,栈的管理等。

Navigation用法

导航组件由以下三个关键部分组成:

  1. 导航图:在一个集中位置包含所有导航相关信息的 XML 资源。这包括应用内所有单个内容区域(称为目标)以及用户可以通过应用获取的可能路径。
  2. NavHost:显示导航图中目标的空白容器。导航组件包含一个默认 NavHost 实现 (NavHostFragment),可显示 Fragment 目标。
  3. NavController:在 NavHost 中管理应用导航的对象。当用户在整个应用中移动时,NavController 会安排 NavHost 中目标内容的交换。

在应用中导航时,您告诉 NavController,您想沿导航图中的特定路径导航至特定目标,或直接导航至特定目标。NavController 便会在 NavHost 中显示相应目标。

导航组件提供各种其他优势,包括以下内容:

  • 处理 Fragment 事务。
  • 默认情况下,正确处理往返操作。
  • 为动画和转换提供标准化资源。
  • 实现和处理深层链接。
  • 包括导航界面模式(例如抽屉式导航栏和底部导航),用户只需完成极少的额外工作。
  • Safe Args - 可在目标之间导航和传递数据时提供类型安全的 Gradle 插件。
  • ViewModel 支持 - 您可以将 ViewModel 的范围限定为导航图,以在图表的目标之间共享与界面相关的数据。

此外,您还可以使用 Android Studio 的 Navigation Editor 来查看和编辑导航图。下面讲一下基本的使用步骤:

一、build.gradle中添加依赖
implementation 'androidx.navigation:navigation-fragment:2.0.0-rc02'
implementation 'androidx.navigation:navigation-ui:2.0.0-rc02'
二、创建Navigation Graph

右键点击res,然后在弹出菜单中选择“new” > “Android Resource File”,填写文件名称,并将Resource Type修改为Navigation,文件夹名称使用默认的navigation,然后点击“OK”创建。

在这里插入图片描述

三、创建NavHostFragment

在Activity中新建一块Fragment的容器,用来放置Fragment

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <fragment
        android:id="@+id/fragment_first"
        // 指向Navigation Gragh
        app:navGraph="@navigation/test_navi"
        // 代表这是Fragment的容器
        android:name="androidx.navigation.fragment.NavHostFragment"
        // 拦截系统返回按钮
        app:defaultNavHost="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
四、在Navigation Gragh中定义各Fragment或者Activity之间的跳转关系即可

下面着重介绍Fragment跳转的几种常见方式:

Fragment跳转Fragment

Navigation Gragh:FragmentB跳转FragmentC

    <fragment
        android:id="@+id/fragmentB"
        android:name="com.skydianshi.testjetpack.Fragment2"
        android:label="fragment2"
        tools:layout="@layout/fragment_fragment2">
        <action
            android:id="@+id/action_fragmentB_to_fragmentC"
            app:destination="@id/fragmentA"
            app:exitAnim="@android:anim/slide_out_right" />
    </fragment>

FragmentB:

    NavHostFragment.findNavController(this).navigate(R.id.action_fragmentB_to_fragmentC,null);

在FragmentB中通过NaviController寻找到对应的跳转action,即可实现跳转到FragmentC

Fragment带参数跳转Fragment

这里采用Navigation的使用safe args传递参数,这种方式可以保证传递时参数类型安全,但需注意的时,该方式采用的是插件化的实现,需要在build.gradle中引入插件:

apply plugin: 'androidx.navigation.safeargs'

Navigation Gragh:

    <fragment
        android:id="@+id/fragmentA"
        android:name="com.skydianshi.testjetpack.Fragment1"
        android:label="fragment1"
        tools:layout="@layout/fragment_fragment1">
        
        // 跳转设置可以在图形化界面中直接连线
        <action
            android:id="@+id/action_fragmentA_to_fragmentB"
            app:destination="@id/fragmentB"
            app:exitAnim="@android:anim/slide_out_right" />
            
        // 参数设置可在图形化界面中直接添加
        <argument
            android:name="name"
            app:argType="string"
            android:defaultValue="fragmentA" />
        <argument
            android:name="age"
            app:argType="integer"
            android:defaultValue="0" />
    </fragment>

FragmentA:

Fragment1Args args = new Fragment1Args
                        .Builder()
                        .setAge(10)
                        .setName("mary")
                        .build();
NavHostFragment.findNavController(this).navigate(R.id.action_fragmentA_to_fragmentB, args.toBundle());

FragmentB:

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // ......省略无关代码......
        Fragment1Args args = Fragment1Args.fromBundle(getArguments());
        String name = args.getName();
        int age = args.getAge();
        Log.e("Fragment2", "Fragment2: " + name + "-----" + age);
        return view;
    }

通过在Gragh中设置参数,编译后会自动生成Fragment1Args参数,通过在FragmentA中配置参数,FragmentB中解析参数,达到参数传递的目的。

任意界面跳转Fragment

Navigation Gragh:

	// 在gragh图形化界面中右击fragment,添加global action即可
    <action android:id="@+id/action_global_fragment3" app:destination="@id/fragment3" />

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

    <action android:id="@+id/action_global_fragmentA" app:destination="@id/fragmentA"/>

Fragment2:

NavHostFragment.findNavController(this).navigate(R.id.action_global_fragment);

MainActivity:

NavController navController = Navigation.findNavController(this, R.id.fragment_first2);
navController.navigate(R.id.action_global_fragment3);

在Navigation Gragh中添加一个global的跳转action,即可通过该action,从其他任何界面跳转至该Fragment,例如上面从Fragment2和MainActivity跳转至Fragment3。

Fragment跳转Activity

Navigation Gragh:

    <fragment
        android:id="@+id/fragment3"
        android:name="com.skydianshi.testjetpack.Fragment3"
        android:label="fragment_3"
        tools:layout="@layout/fragment_3" >

        <action
            android:id="@+id/action_fragment3_to_secondActivity"
            app:destination="@id/secondActivity" />
    </fragment>

Fragment3:

NavHostFragment.findNavController(this).navigate(R.id.action_fragment3_to_secondActivity);
Navigation缺点

通过查看Navigation的源码实现,可以发现Fragment之间的跳转是通过反射的方式新建了一个新的Fragment扔到栈中,这就意味着无法复用之前的Fragment,举个例子:

  • FragmentA->FragmentB->FragmentA

这样一个跳转,第二个FragmentA和第一个FragmentA是两个实例,二者无任何关系,也就不存在复用问题了,这个问题在BottomNavigation中尤为突出,在切换botttom tab时无法保存之前的Fragment状态,每次都是新的Fragment,一则是资源的浪费,二则是用户体验也不佳。

解决这个问题目前只有临时方案,即在Bottom navigation的情况下,防止多个FragmentHost,各自实现自己的栈空间,这样可以临时解决一下,但并不优雅。最终还是要等Navigation的更新,希望新的版本可以解决这个问题。

更详细的使用方法可以参考JetPack学习笔记之Navigation
更深入点儿可以参考JetPack之Navigation基本用法
B站上有个学习视频Android开发Jetpack系列之Navigation【完结】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值