Navigation 的 源码分析
NavHostFragment 的生命周期方法,断点流程
onInflate ---->onAttach--->onCreate--->onCreateNavController
--->createFragmentNavigator--->onCreateView--->onViewCreated
--->onPrimaryNavigationFragmentChanged
NavHostFragment#create API 入口
1. onInflate
解析XML,主要解析布局文件两个属性
graphResId 设置,保存KEY_GRAPH_ID
startDestinationArgs,保存目标参数,KEY_START_DESTINATION_ARGS
最终创建实例 new NavHostFragment,并讲inflate出来属性绑定
2. onCreate
导航初始化
无论是XML实现还是代码实现,都会执行Fragment的onCreate方法.
NavController在这里被创建,并且NavHostFragment中有一个NavController对象。
(1)初始化NavController,NavController为导航的控制类,核心类。
mNavController = new NavHostController(context);
(2)if (savedInstanceState != null) {开始恢复状态}
(3)if (mGraphId != 0) {设置导航图信息}
初始化new NavHostController
- 其中mNavigatorProvider是NavController中的全局变量,内部通过HashMap键值对的形式保存Navigator类。
onCreateNavController
- createFragmentNavigator
在实现导航的时候,我们需要根据navigation配置文件生成NavGraph类,然后在根据每个不同的action id,找到对应的NavDestination就可以实现页面导航跳转了。
mNavController.getNavigatorProvider().addNavigator(createFragmentNavigator());
构建了FragmentNavigator对象,其中抽象类Navigator还有个重要的实现类ActivityNavigator和NavGraphNavigator。
这个两个类的对象在NavController的构造方法中被添加。
其中Navigator类的作用是:能够实例化对应的NavDestination,并且能够实现导航功能,拥有自己的回退栈。
.setGraph()
构建NavGraph
在构建NavController的时候,我们还调用了NavController.setGraph(graphId)方法,
该方法主要是构建NavGraph。
调用getNavInflater方法创建NavInflater对象,用于解析navigation xml
NavInflater.inflate方法
根据传入的XML资源id构建NavGraph,NavGraph组成Fragment路由的导航地图,而NavDestination代表了导航的每一个目的地。在解析完NavDestination后,需要要求NavDestination为NavGraph,即NavGraph是NavDestination的子类。而且在NavGraph内部存储了NavDestination信息。
(1)getNavigator方法获取都Navigator实例,该实例在构建NavController是被添加进去,这里获取的是FragmentNavigator对象。
(2)createDestination方法,会调用FragmentNavigator的createDestination构建Destination对象。
(3)onInflate方法,解析destination XML
(4)while循环内部通过递归构建导航图。
通过NavInflater类之后,解析了XML文件构建整个Graph之后。,
下面回到setGraph方法,在解析完XML后会,
回到NavHostFragment.setGraph方法。
(1)popBackStackInternal方法将回退栈中的信息全部出栈。
(2)调用onGraphCreated主要是显示一个导航Fragment视图。
onGraphCreated方法
---- NavController#navigate
(1)恢复之前的导航状态
(2)调用navigate方法,显示第一个Fragment。即在Navigation文件里,属性app:startDestination的Fragment。所以最终都会走到navigate导航方法。
3. onCreateView
NavHostFragment.onCreateView方法
该NavHostFragment的视图就只有一个FragmentContainerView extends FrameLayout
containerView.setId(getContainerId());//这行主要用于以代码方式添加fragment
4. onViewCreated
NavHostFragment.onViewCreated
//把mNavController记录在view的tag中
Navigation.setViewNavController(view, mNavController);
获取NavController
1.获取NavController
NavHostFragment.findNavController(fragment)
2.findNavController方法 该方法没什么实质性的代码,只要是调用了findViewNavController方法。
3.findViewNavController方法 通过view.tag查找NavController。内部调用了getViewNavController方法。
4.getViewNavController方法 通过获取view的Tag,获取NavController对象,这里的tag ID和setViewNavController都是nav_controller_view_tag。
导航
1.在构建和获取到NavController对象以及NavGraph之后。,
下面是使用它来实现真正的导航了。下面从navigate开始分析。在navigate方法内部会查询到NavDestination,然后根据不同的Navigator实现页面导航。
navigate 方法
(1)如果回退栈为null返回NavGraph,不为null返回回退栈中的最后一项。
NavDestination currentNode = mBackStack.isEmpty()
? mGraph
: mBackStack.getLast().getDestination();
(2)根据id,获取对应的NavAction。然后在通过NavAction获取目的地id。
final NavAction navAction = currentNode.getAction(resId);
destId = navAction.getDestinationId();
(4)利用目的地ID属性,通过findDestination方法,找到准备导航的目的地。
NavDestination node = findDestination(destId);
(5)开始导航
1.navigate(node, combinedArgs, navOptions, navigatorExtras);
2.NavDestination newDest = navigator.navigate(node, finalArgs,
navOptions, navigatorExtras);
2.FragmentNavigator的实现
通过以上的分析,又来到了Navigator 的子类FragmentNavigator类。下面来看看FragmentNavigator.navigate的方法。
(1)调用instantiateFragment,通过反射机制构建Fragment实例
(2)处理进出场等动画逻辑
(3)最终调用FragmentManager来处理导航逻辑。
**ActivityNavigator最终也是调用了startActivity方法
- 综上
(1)NavHostFragment 作为导航载体,在Activity的layout文件里被引用(或者在代码中动态),并且持有导航控制类NavController引用。
(2)NavController 将导航任务委托给Navigator类,Navigator类有两个重要的子类FragmentNavigator和ActivityNavigator子类。NavController类持有NavInflater类引用。
(3)NavInflater 负责解析Navgation文件,负责构建NavGraph导航图。
(4)NavDestination 存有各个目的地信息,在FragmentNavigator和ActivityNavigator内部分别对应一个Destination类,该类继承NavDestination。
(5)在页面导航时,fragment的操作还是交由FragmentManager在操作,activity交由startActivity执行。