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”创建。

Jetpack学习之Navigation_第1张图片

三、创建NavHostFragment

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




    


四、在Navigation Gragh中定义各Fragment或者Activity之间的跳转关系即可

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

Fragment跳转Fragment

Navigation Gragh:FragmentB跳转FragmentC

    
        
    

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:

    
        
        // 跳转设置可以在图形化界面中直接连线
        
            
        // 参数设置可在图形化界面中直接添加
        
        
    

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即可
    

    

    

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:

    

        
    

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【完结】

你可能感兴趣的:(Android,JAVA,android,java)