【Android】浅谈Navigation

一,概述

androidx.navigation封装了FragmentManager CRUD操作,简化了单Actively多Fragment架构,本文着重解析Navigation设计思路,底层实现

二,原理

1,inflate

FragmentContainerView设置name参数为NavHostFragment,并且传入navGraph参数,在NavHostFragment#onInflate回调中,便会解析navGraph,如下。

inflate阶段主要保存所有声明的导航判断,其声明内容在哦res/navigation/目录下的xml,如下

大致定义了fragment标签、action标签、以及arguments和include。include可以包含其他导航判断,这个在navigate详细讲解。

回到Inflate解析阶段,做了两件事,如下

保存graphId和mDefualtNavHost参数,在onCreate开始解析,跟进到onCreate

onCreate中初始化NavHostController,并且设置Graph到controller中,

NavHostController中依赖了Navigator接口,Navigator即导航者抽象类,如下

其关键抽象方法定义如下

即navigate和popBackStack。具体实现主要是如下类

在此读者简单解释下几个实现类,

FragmentNavigator:负责Fragment的导航

ActivityNavigator:负责Activity跳转导航

NavGraphNavigator:负责include片段定义的Graph,即跳转到其他Graph的导航

在NavController中,预先add了两个Navigator,NavGraphNavigator和ActivityNavigatror

在onCreateView回调中,再次添加了DIalogFragmentNavigator和FragmentNavigator,

回到正题,跟进解析Graph逻辑

NavInflater#inflate方法解析了graph xml文件,生成一个NavGraph对象,NavGraph是NavDestination子类。笔者在此简单解释下NavDestination。

一个Navdestination存储了导航Id,Name和label,即具体的导航信息

NavGraph和NavDestination关系如同View和ViewGroup,NavGraph包含了多个NavDestination,存储在mNodes成员中,

跟进NavInflater#inflate方法

1,如上,拿到element name,获取Navigator,调用onCreateDestination方法创建一个Navdestionation,并且回调onInflate方法绑定参数。

以FragmentNavigator为例,createDestionation方法实现如下,简单将FragmentNavigatir传入Navdestionation,并且绑定具体Fragment的ClassName

2,解析include、argument和action标签,setGraph由于是root节点解析,会从NavGraphNavigaotr创建一个NavDestionation,并绑定startDestId参数,如下,

随后,将虽有的Destionation添加到NavGraph,包括fragment片段和action等

3,action的解析

拿到launchSingTop、转场动画、popUpTo、argument标签等,存到NavAction中。然后NavAction被保存到NavDestionation中,类似activity tag和action tag的关系。

因此,setGraph解析了所有xml中的导航意图(NavDestionation),这个NavGraph被NavController持有,继续跟进下startId的显示。

2,startId

这里谈下staretId的展示

DefaultNavHost为true,NavFragmentHost会被设置为PrimaryNavigationFragment,作为导航Fragment,back优先回调其popBackStack方法,

在NavController的setGraph中,inflate解析的NavGraph存储到mGraph成员,并且回调onCraphCreated回调

onCraphCreated最后一段,会调用navigate方法,如下

mGraoh即NavGraph,navigate这个NavGraph,会调用NavGraphNavitor#navigate方法,

拿到startDestination,如果没有则抛出异常。因此,setGraph就会navigate到startid,如果存在的话。

3,navigate

接2讲起,startId拿到navigator,这里以fragment为例。

1,反射newInstance一个Fragment,通过setArgument设置navigate的参数

2,ft中绑定自定义动效

3,处理isSingleTopReplacement逻辑,popBackStack稍后讲解。

最后通过ft#commit,再将destionation存到FragmentNavigor的mBackStack中,返回NavDestionation,

4,navigator返回了navDestionation,NavController再进行Stack处理,将navDestionation再次封装为NavBackStackEntry实例,放到NavController#mBackStack中

NavBackStackEntry可以理解为具体的Fragment实例抽象,其实现了LifeCyclerOwner接口,

NavController监听了LifeCycler,在onStateChanged中,进一步调用NavBackStackEntry#handleLifecycleEvent方法,

LifeCyclerOwner是NavFragmentHost,onCreate传入,因此NavFragmentHost的LifeCycler变化会同步到所有的BackStackEntry#LifeCycler中

但是navigate的lifeCycle变化,则是在dispatchOndestinationChanged回调中由NavController控制,

dispatchOndestinationChanged与navigate和pop操作挂钩

4,popBackStack

NavController#popBackStack方法如下

跟进

popped为true,则会触发displatchOnDestionationChanged方法,执行lifeCycle

跟进popBackStackInternal

1,根据pop的destinationId,拿到Navigator,放到popOperations容器。popBackStack的destinationId就是currentId,inclusive参数为true

2,找到了destinationId,break

3,如果没有找到destinationId,打印日志返回

4,调用navigator的popBackStack方法,有多少给id被pop,则调用多少次。即popOperations容器会放置多个重复的Navigator实例,代表需要顺序pop多少次。并且此处会触发NavBackStackEntry#Destroy回调

跟进Navigtor的popBackStack,此处还是以FragmentNavigtor为例

调用fm#popBackStack方法,并且移除mBackStack最后一个。

最后,调用displatchOnDestionationChanged方法,将mBackStack所有Entry走到合适周期,

相关推荐
消失的旧时光-19431 小时前
Android 系统层扫盲 09:AMS、ATMS、WMS、PMS 到底分别管什么?
android·wms·pms·ams·aosp·atms
Godikov1 小时前
Android 系统级设备应用踩坑实录:sharedUserId 签名、SDK 授权失败 -4、开机自启与 U 盘 OTA 升级
android
IT毕设实战小研4 小时前
基于大数据的国内主要农作物产量趋势分析与可视化
android·java·大数据·django·课程设计
企业数字化笔记5 小时前
固定资产历史数据怎么导入系统?Excel模板、字段映射和数据校验
android·java·数据库·后端
龙之叶6 小时前
Android出海系列-GMS认证介绍
android
潮族大Z6 小时前
Android性能优化:启动、内存、卡顿的一站式排查手册
android
事圆则缓7 小时前
从suspend字节码到 Retrofit 协程桥:挂起函数识别与恢复
android·retrofit
杉氧8 小时前
RN 性能调优指南:重渲染(Re-renders)控制与长列表(FlatList)优化
android·前端·react native
Coffeeee9 小时前
claude-video 一个让你的Agent拥有看视频能力的Skill
android·人工智能·aigc
菜鸟~noob23310 小时前
【电子战】第07篇:多普勒测向【含matlab代码】
android·开发语言·matlab