一,概述
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走到合适周期,


1063

被折叠的 条评论
为什么被折叠?



