Jetpack Navigation 原理浅析

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容