Jetpack Navigation 原理浅析

作者: zcwfeng | 来源:发表于2021-01-23 13:31 被阅读0次

    Navigation 的 源码分析

    2021-01-23 12.37.54.png

    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. 综上
    nav2021_2.jpeg

    (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执行。

    相关文章

      网友评论

        本文标题:Jetpack Navigation 原理浅析

        本文链接:https://www.haomeiwen.com/subject/dqxuzktx.html