Android Navigation 原理解析
1. nav_graph.xml 如何生成路由表 NavGraph
解析流程与原理
关键技术点:
-
XML 解析:
-
使用
XmlResourceParser
解析 XML 文件 -
遍历所有节点(
<fragment>
,<activity>
,<navigation>
等)
-
-
Destination 创建:
-
根据标签名获取对应的
Navigator
-
调用
Navigator.createDestination()
创建具体目标 -
解析节点属性(id、label、arguments 等)
-
-
NavGraph 构建:
-
维护节点树结构
-
处理嵌套导航图(递归解析)
-
建立 action 连接关系
-
核心源码解析:
// NavInflater.java
public NavGraph inflate(@XmlRes int graphResId) {// 获取XML解析器XmlResourceParser parser = mContext.getResources().getXml(graphResId);// 创建空导航图NavGraph graph = new NavGraph(this);while (parser.next() != XmlPullParser.END_DOCUMENT) {if (parser.getEventType() != XmlPullParser.START_TAG) continue;String tagName = parser.getName();// 获取对应标签的NavigatorNavigator navigator = mNavigatorProvider.getNavigator(tagName);// 创建DestinationNavDestination destination = navigator.createDestination();// 解析属性destination.onInflate(mContext, parser);if (destination instanceof NavGraph) {// 递归解析嵌套图inflateChildren(parser, (NavGraph)destination);}// 添加到导航图graph.addDestination(destination);}return graph;
}
2. startDestinationId 启动页加载机制
启动流程原理
关键实现细节:
-
启动时机:
-
NavHostFragment 的
onCreate()
方法中初始化 -
首次设置导航图时触发启动流程
-
-
导航执行:
-
通过
FragmentNavigator.navigate()
执行 -
使用反射创建 Fragment 实例:
final Fragment fragment = mFragmentManager.getFragmentFactory().instantiate(mContext.getClassLoader(), dest.getClassName());
-
-
事务处理:
-
使用
FragmentTransaction.replace()
替换容器内容 -
提交事务后立即执行(
commitNow()
)
-
源码关键路径:
// NavController.java
public void setGraph(@NavGraphRes int graphResId) {mGraph = mNavInflater.inflate(graphResId);onGraphCreated(); // 触发首次导航
}private void onGraphCreated() {if (mBackStack.isEmpty()) {// 导航到起始目标navigate(mGraph, mGraph.getStartDestination(), null, null);}
}// FragmentNavigator.java
public NavDestination navigate(...) {// 创建Fragment实例final Fragment frag = instantiateFragment(context, className, args);final FragmentTransaction ft = mFragmentManager.beginTransaction();// 执行替换操作ft.replace(mContainerId, frag);ft.commit();return destination;
}
3. Fragment 页面切换为何执行 onDestroyView
根本原因分析
设计原理:
-
默认行为:
-
FragmentNavigator
使用replace()
而非show/hide
-
替换操作会销毁上一个 Fragment 的视图
-
-
生命周期对比:
导航方式 前Fragment生命周期 新Fragment生命周期 replace() onPause→onDestroyView onCreateView→onResume show/hide() onPause onResume -
官方设计考量:
-
确保状态一致性
-
避免视图叠加导致的潜在问题
-
简化内存管理
-
性能影响:
-
优点:严格的内存管理,避免泄露
-
缺点:
-
视图重建开销(特别是复杂UI)
-
状态保存/恢复复杂化
-
影响转场动画流畅性
-
4. singleTop 失效问题深度解析
问题现象与原因
源码级分析:
// FragmentNavigator.java
public NavDestination navigate(...) {// 无单例模式检查逻辑!// 始终创建新实例final Fragment frag = instantiateFragment(...);// 始终执行replaceft.replace(mContainerId, frag);
}
与 Activity singleTop 对比:
特性 | Activity singleTop | Fragment "singleTop" |
---|---|---|
栈顶复用 | 调用 onNewIntent() | 始终重建 |
生命周期 | 无销毁/重建 | 完整生命周期 |
实现机制 | 框架原生支持 | Navigation 未实现 |
官方未修复原因:
-
架构限制:
-
Fragment 无内置任务栈管理
-
缺乏类似
onNewIntent()
的回调机制
-
-
状态一致性:
-
确保每次导航都传递新参数
-
避免状态污染
-
-
设计选择:
-
优先保证导航行为一致性
-
牺牲特殊场景优化
-