最近项目中用到了很多Jetpack相关的东西,决定把Jetpack从头到尾撸一遍,先撸了一下Navigation,通过一些简单的代码记录一下比较关键的东西。
借用Jetpack官方介绍,Navigation是指支持用户导航、进入和退出应用中不同内容片段的交互。Android Jetpack 的Navigation组件可帮助您实现导航,无论是简单的按钮点击,还是应用栏和抽屉式导航栏等更为复杂的模式,该组件均可应对。Navigation组件还通过遵循一套既定原则来确保一致且可预测的用户体验。
简单来说,Jetpack-Navigation组件可以让我们更为方便地管理Fragment的切换,包括参数传递,切换动画,栈的管理等。
导航组件由以下三个关键部分组成:
在应用中导航时,您告诉 NavController,您想沿导航图中的特定路径导航至特定目标,或直接导航至特定目标。NavController 便会在 NavHost 中显示相应目标。
导航组件提供各种其他优势,包括以下内容:
此外,您还可以使用 Android Studio 的 Navigation Editor 来查看和编辑导航图。下面讲一下基本的使用步骤:
implementation 'androidx.navigation:navigation-fragment:2.0.0-rc02'
implementation 'androidx.navigation:navigation-ui:2.0.0-rc02'
右键点击res,然后在弹出菜单中选择“new” > “Android Resource File”,填写文件名称,并将Resource Type修改为Navigation,文件夹名称使用默认的navigation,然后点击“OK”创建。
在Activity中新建一块Fragment的容器,用来放置Fragment
下面着重介绍Fragment跳转的几种常见方式:
Navigation Gragh:FragmentB跳转FragmentC
FragmentB:
NavHostFragment.findNavController(this).navigate(R.id.action_fragmentB_to_fragmentC,null);
在FragmentB中通过NaviController寻找到对应的跳转action,即可实现跳转到FragmentC
这里采用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中解析参数,达到参数传递的目的。
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。
Navigation Gragh:
Fragment3:
NavHostFragment.findNavController(this).navigate(R.id.action_fragment3_to_secondActivity);
通过查看Navigation的源码实现,可以发现Fragment之间的跳转是通过反射的方式新建了一个新的Fragment扔到栈中,这就意味着无法复用之前的Fragment,举个例子:
这样一个跳转,第二个FragmentA和第一个FragmentA是两个实例,二者无任何关系,也就不存在复用问题了,这个问题在BottomNavigation中尤为突出,在切换botttom tab时无法保存之前的Fragment状态,每次都是新的Fragment,一则是资源的浪费,二则是用户体验也不佳。
解决这个问题目前只有临时方案,即在Bottom navigation的情况下,防止多个FragmentHost,各自实现自己的栈空间,这样可以临时解决一下,但并不优雅。最终还是要等Navigation的更新,希望新的版本可以解决这个问题。
更详细的使用方法可以参考JetPack学习笔记之Navigation
更深入点儿可以参考JetPack之Navigation基本用法
B站上有个学习视频Android开发Jetpack系列之Navigation【完结】