Navigation(一)
2021-11-25 本文已影响0人
涛涛123759
前言
![](https://img.haomeiwen.com/i1728460/9283ae5a77f75544.png)
一、实例化 NavHostFragment
NavHostFragment#create
@NonNull
public static NavHostFragment create(@NavigationRes int graphResId) {
return create(graphResId, null);
}
@NonNull
public static NavHostFragment create(@NavigationRes int graphResId,
@Nullable Bundle startDestinationArgs) {
Bundle b = null;
if (graphResId != 0) {
b = new Bundle();
b.putInt(KEY_GRAPH_ID, graphResId); // 把graphID存入到Bundle
}
if (startDestinationArgs != null) {
if (b == null) {
b = new Bundle();
}
b.putBundle(KEY_START_DESTINATION_ARGS, startDestinationArgs);
}
//初始化此对象
final NavHostFragment result = new NavHostFragment();
if (b != null) {
result.setArguments(b);
}
return result;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (!(view instanceof ViewGroup)) {
throw new IllegalStateException("created host view " + view + " is not a ViewGroup");
}
Navigation.setViewNavController(view, mNavController); // 会把我们的 mNavController 加入到 Navigation里面去
// 说白了,如果是代码的方式去写的话,并非是xml的写法的话,就做下面的代码,但是 大部分都是 xml的形式
// 当以编程方式添加时,我们需要在父级上设置 NavController - 即具有与此 NavHostFragment 匹配的 ID 的视图
// When added programmatically, we need to set the NavController on the parent - i.e.,
// the View that has the ID matching this NavHostFragment.
if (view.getParent() != null) {
mViewParent = (View) view.getParent();
if (mViewParent.getId() == getId()) {
Navigation.setViewNavController(mViewParent, mNavController);
}
}
}
二、生命周期流程
从NavHostFragment.onInflate
开始
public void onInflate(@NonNull Context context, @NonNull AttributeSet attrs,
@Nullable Bundle savedInstanceState) {
super.onInflate(context, attrs, savedInstanceState);
final TypedArray navHost = context.obtainStyledAttributes(attrs,
androidx.navigation.R.styleable.NavHost);
//fragment 控制器集合
final int graphId = navHost.getResourceId(
androidx.navigation.R.styleable.NavHost_navGraph, 0);
// 就把此属性解析出来,activity_main.xml 的 app:navGraph="@navigation/nav_graph_main"
if (graphId != 0) {
mGraphId = graphId;
}
navHost.recycle();
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NavHostFragment);
//拦截系统back键
final boolean defaultHost = a.getBoolean(R.styleable.NavHostFragment_defaultNavHost, false);
// 就把此属性解析出来,activity_main.xml 的 app:defaultNavHost="true"
if (defaultHost) {
mDefaultNavHost = true;
}
a.recycle();
}
三、创建控制器
@CallSuper
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
final Context context = requireContext();
// 此处 实例化出 NavHostController 控制器
mNavController = new NavHostController(context);
mNavController.setLifecycleOwner(this);
mNavController.setOnBackPressedDispatcher(requireActivity().getOnBackPressedDispatcher());
// Set the default state - this will be updated whenever
// onPrimaryNavigationFragmentChanged() is called
mNavController.enableOnBackPressed(
mIsPrimaryBeforeOnCreate != null && mIsPrimaryBeforeOnCreate);
mIsPrimaryBeforeOnCreate = null;
mNavController.setViewModelStore(getViewModelStore());
//创建和添加导航
onCreateNavController(mNavController);
// 下面代码是容错处理
Bundle navState = null;
if (savedInstanceState != null) {
navState = savedInstanceState.getBundle(KEY_NAV_CONTROLLER_STATE);
if (savedInstanceState.getBoolean(KEY_DEFAULT_NAV_HOST, false)) {
mDefaultNavHost = true;
getParentFragmentManager().beginTransaction()
.setPrimaryNavigationFragment(this)
.commit();
}
mGraphId = savedInstanceState.getInt(KEY_GRAPH_ID);
}
if (navState != null) {
// Navigation controller state overrides arguments
mNavController.restoreState(navState);
}
if (mGraphId != 0) { // 如果GraphID不等于空
// Set from onInflate()
// 设置GraphID,此处意义重大,会获取nav_graph_main里面的action等导航信息
mNavController.setGraph(mGraphId);
} else {
// See if it was set by NavHostFragment.create()
final Bundle args = getArguments();
final int graphId = args != null ? args.getInt(KEY_GRAPH_ID) : 0;
final Bundle startDestinationArgs = args != null
? args.getBundle(KEY_START_DESTINATION_ARGS)
: null;
if (graphId != 0) {
//设置资源
mNavController.setGraph(graphId, startDestinationArgs);
}
}
super.onCreate(savedInstanceState);
}
调用NavHostFragment.onCreateNavController
方法
private NavigatorProvider mNavigatorProvider = new NavigatorProvider();
@CallSuper
protected void onCreateNavController(@NonNull NavController navController) {
// 这里是通过导航暴露者,获取到 NavigationProvider 对象
navController.getNavigatorProvider().addNavigator(
new DialogFragmentNavigator(requireContext(), getChildFragmentManager()));
navController.getNavigatorProvider().addNavigator(createFragmentNavigator());
}
public NavigatorProvider getNavigatorProvider() {
return mNavigatorProvider;
}
创建 fragment 导航
protected Navigator<? extends FragmentNavigator.Destination> createFragmentNavigator() {
// 此ID,如果不写xml文件,单纯用代码实现的时候,需要得到一个父容器ID
return new FragmentNavigator(requireContext(), getChildFragmentManager(), getContainerId());
}
private int getContainerId() {
int id = getId();
if (id != 0 && id != View.NO_ID) {
return id;
}
return R.id.nav_host_fragment_container;
}
四、NavigatorProvider 导航管理器
- 在
NavigatorProvider
导航控制器类中进行保存 fragment 的导航类
public class NavigatorProvider {
// 把导航页面,例如 三个Fragment保存 与 key保存 记录
private static final HashMap<Class<?>, String> sAnnotationNames = new HashMap<>();
//存放导航集合
private final HashMap<String, Navigator<? extends NavDestination>> mNavigators = new HashMap<>();
//获取导航的 name ,并保持到集合 sAnnotationNames 中
@NonNull
static String getNameForNavigator(@NonNull Class<? extends Navigator> navigatorClass) {
//从集合中获取对象
String name = sAnnotationNames.get(navigatorClass);
if (name == null) {
//获取 name 注解
Navigator.Name annotation = navigatorClass.getAnnotation(Navigator.Name.class);
//获取值 name(导航)
name = annotation != null ? annotation.value() : null;
if (!validateName(name)) {
throw new IllegalArgumentException("No @Navigator.Name annotation found for "
+ navigatorClass.getSimpleName());
}
//把name(导航)保存到集合中
sAnnotationNames.put(navigatorClass, name);
}
return name;
}
//添加导航
@Nullable
public final Navigator<? extends NavDestination> addNavigator(
@NonNull Navigator<? extends NavDestination> navigator) {
//navigator 是 DialogFragmentNavigator 的实例
String name = getNameForNavigator(navigator.getClass());
return addNavigator(name, navigator);
}
//获取导航
public <T extends Navigator<?>> T getNavigator(@NonNull String name) {
if (!validateName(name)) {
throw new IllegalArgumentException("navigator name cannot be an empty string");
}
//根据 name 获取导航
Navigator<? extends NavDestination> navigator = mNavigators.get(name);
if (navigator == null) {
throw new IllegalStateException("Could not find Navigator with name \"" + name
+ "\". You must call NavController.addNavigator() for each navigation type.");
}
return (T) navigator;
}
}
五、导航页面 Navigator
Navigator
是作为中间层解决高耦合低扩展的问题
实现类有:
- DialogFragmentNavigator
- FragmentNavigator
- ActivityNavigator
- NavGraphNavigator
- NoOpNavigator
5.1、DialogFragmentNavigator 导航
- 创建导航页面
Navigator
,我们按上面的DialogFragmentNavigator
分析
//注解 Navigator.Name 主要获取那个导航
@Navigator.Name("dialog")
public final class DialogFragmentNavigator extends Navigator<DialogFragmentNavigator.Destination> {
private final Context mContext;
private final FragmentManager mFragmentManager;
private int mDialogCount = 0;
private final HashSet<String> mRestoredTagsAwaitingAttach = new HashSet<>();
public DialogFragmentNavigator(@NonNull Context context, @NonNull FragmentManager manager) {
mContext = context;
mFragmentManager = manager;
}
public NavDestination navigate(@NonNull final Destination destination, @Nullable Bundle args,
@Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
if (mFragmentManager.isStateSaved()) {
Log.i(TAG, "Ignoring navigate() call: FragmentManager has already"
+ " saved its state");
return null;
}
String className = destination.getClassName();
if (className.charAt(0) == '.') {
className = mContext.getPackageName() + className;
}
final Fragment frag = mFragmentManager.getFragmentFactory().instantiate(
mContext.getClassLoader(), className);
if (!DialogFragment.class.isAssignableFrom(frag.getClass())) {
throw new IllegalArgumentException("Dialog destination " + destination.getClassName()
+ " is not an instance of DialogFragment");
}
final DialogFragment dialogFragment = (DialogFragment) frag;
dialogFragment.setArguments(args);
//绑定 lifecycle
dialogFragment.getLifecycle().addObserver(mObserver);
//显示fragment
dialogFragment.show(mFragmentManager, DIALOG_TAG + mDialogCount++);
return destination;
}
public static class Destination extends NavDestination implements FloatingWindow {
private String mClassName;
public Destination(@NonNull NavigatorProvider navigatorProvider) {
this(navigatorProvider.getNavigator(DialogFragmentNavigator.class));
}
public Destination(@NonNull Navigator<? extends Destination> fragmentNavigator) {
super(fragmentNavigator);
}
@CallSuper
@Override
public void onInflate(@NonNull Context context, @NonNull AttributeSet attrs) {
super.onInflate(context, attrs);
TypedArray a = context.getResources().obtainAttributes(attrs,
R.styleable.DialogFragmentNavigator);
String className = a.getString(R.styleable.DialogFragmentNavigator_android_name);
if (className != null) {
setClassName(className);
}
a.recycle();
}
@NonNull
public final Destination setClassName(@NonNull String className) {
mClassName = className;
return this;
}
@NonNull
public final String getClassName() {
if (mClassName == null) {
throw new IllegalStateException("DialogFragment class was not set");
}
return mClassName;
}
}
}
5.2、FragmentNavigator 导航
public class FragmentNavigator extends Navigator<FragmentNavigator.Destination> {
private static final String TAG = "FragmentNavigator";
private static final String KEY_BACK_STACK_IDS = "androidx-nav-fragment:navigator:backStackIds";
private final Context mContext;
private final FragmentManager mFragmentManager;
private final int mContainerId;
private ArrayDeque<Integer> mBackStack = new ArrayDeque<>();
public FragmentNavigator(@NonNull Context context, @NonNull FragmentManager manager,
int containerId) {
mContext = context;
mFragmentManager = manager;
mContainerId = containerId;
}
//创建目的地
public Destination createDestination() {
return new Destination(this);
}
}
-
FragmentNavigator#navigate
导航
@Nullable
@Override
public NavDestination navigate(@NonNull Destination destination, @Nullable Bundle args,
@Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
if (mFragmentManager.isStateSaved()) {
Log.i(TAG, "Ignoring navigate() call: FragmentManager has already"
+ " saved its state");
return null;
}
// 根据Destination目的地,获取到第一个Fragmet 也就是 MainPage1Fragment实例
// 下面代码是反射 去 实例化 我们的 第一个Fragment
String className = destination.getClassName();
if (className.charAt(0) == '.') {
className = mContext.getPackageName() + className;
}
// instanceFragment反射的细节,可以看看
final Fragment frag = instantiateFragment(mContext, mFragmentManager,
className, args);
frag.setArguments(args);
final FragmentTransaction ft = mFragmentManager.beginTransaction();
// Fragment的进出 动画
int enterAnim = navOptions != null ? navOptions.getEnterAnim() : -1;
int exitAnim = navOptions != null ? navOptions.getExitAnim() : -1;
int popEnterAnim = navOptions != null ? navOptions.getPopEnterAnim() : -1;
int popExitAnim = navOptions != null ? navOptions.getPopExitAnim() : -1;
if (enterAnim != -1 || exitAnim != -1 || popEnterAnim != -1 || popExitAnim != -1) {
enterAnim = enterAnim != -1 ? enterAnim : 0;
exitAnim = exitAnim != -1 ? exitAnim : 0;
popEnterAnim = popEnterAnim != -1 ? popEnterAnim : 0;
popExitAnim = popExitAnim != -1 ? popExitAnim : 0;
ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim);
}
// 然后把mContainerId,替换到ft,相当于把 我们的 第一个Fragment加入到了 UI上面了
// 就是把 MainPage1Fragment 加入到 activity_main.xml 的 FragmentContainerView
// mContainerId(就是 FragmentContainerView)相当于容器
// frag(就是 我们的第一个Fragment实例 MainPage1Fragment)
ft.replace(mContainerId, frag);
ft.setPrimaryNavigationFragment(frag);
final @IdRes int destId = destination.getId();
final boolean initialNavigation = mBackStack.isEmpty();
// TODO Build first class singleTop behavior for fragments
final boolean isSingleTopReplacement = navOptions != null && !initialNavigation
&& navOptions.shouldLaunchSingleTop()
&& mBackStack.peekLast() == destId;
boolean isAdded;
if (initialNavigation) {
isAdded = true;
} else if (isSingleTopReplacement) {
// Single Top means we only want one instance on the back stack
if (mBackStack.size() > 1) {
mFragmentManager.popBackStack(
generateBackStackName(mBackStack.size(), mBackStack.peekLast()),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
ft.addToBackStack(generateBackStackName(mBackStack.size(), destId));
}
isAdded = false;
} else {
ft.addToBackStack(generateBackStackName(mBackStack.size() + 1, destId));
isAdded = true;
}
if (navigatorExtras instanceof Extras) {
Extras extras = (Extras) navigatorExtras;
for (Map.Entry<View, String> sharedElement : extras.getSharedElements().entrySet()) {
ft.addSharedElement(sharedElement.getKey(), sharedElement.getValue());
}
}
ft.setReorderingAllowed(true);
//提交任务,并执行fragment的生命周期
ft.commit();
// The commit succeeded, update our view of the world
if (isAdded) {
mBackStack.add(destId);
return destination;
} else {
return null;
}
}
- 实例 fragment
@Deprecated
@NonNull
public Fragment instantiateFragment(@NonNull Context context,
@NonNull FragmentManager fragmentManager,
@NonNull String className, @SuppressWarnings("unused") @Nullable Bundle args) {
// instantiate 反射的细节看看
return fragmentManager.getFragmentFactory().instantiate(
context.getClassLoader(), className);
}
- 在
FragmentFactory#instantiate
的方法中通过反射获取 fragment
@NonNull
public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) {
try {
Class<? extends Fragment> cls = loadFragmentClass(classLoader, className);
return cls.getConstructor().newInstance(); // 把最终方式的Fragment结果 给返回
} catch (java.lang.InstantiationException e) {
throw new Fragment.InstantiationException("Unable to instantiate fragment " + className
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (IllegalAccessException e) {
throw new Fragment.InstantiationException("Unable to instantiate fragment " + className
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (NoSuchMethodException e) {
throw new Fragment.InstantiationException("Unable to instantiate fragment " + className
+ ": could not find Fragment constructor", e);
} catch (InvocationTargetException e) {
throw new Fragment.InstantiationException("Unable to instantiate fragment " + className
+ ": calling Fragment constructor caused an exception", e);
}
}
六、NavController 控制器
- 设置资源
public void setGraph(@NavigationRes int graphResId, @Nullable Bundle startDestinationArgs) {
setGraph(getNavInflater().inflate(graphResId), startDestinationArgs);
}
public void setGraph(@NonNull NavGraph graph) {
setGraph(graph, null);
}
public NavInflater getNavInflater() {
if (mInflater == null) {
//初始化 NavInflater
mInflater = new NavInflater(mContext, mNavigatorProvider);
}
return mInflater;
}
// 可以看到 把 GraphID xml 里面的内容 转变成 NavGraph对象了
public void setGraph(@NonNull NavGraph graph, @Nullable Bundle startDestinationArgs) {
if (mGraph != null) {
// 对象信息有了后,先从栈里面去弹,看能不能弹出来,第一次肯定是弹不出来的
popBackStackInternal(mGraph.getId(), true);
}
// 先把对象 保存到成员
mGraph = graph;
// 此函数就能看到,如何把我们的默认Fragment UI给显示出来了
onGraphCreated(startDestinationArgs);
}
NavController#onGraphCreated
private void onGraphCreated(@Nullable Bundle startDestinationArgs) {
if (mNavigatorStateToRestore != null) {
ArrayList<String> navigatorNames = mNavigatorStateToRestore.getStringArrayList(
KEY_NAVIGATOR_STATE_NAMES);
if (navigatorNames != null) {
for (String name : navigatorNames) {
Navigator<?> navigator = mNavigatorProvider.getNavigator(name);
Bundle bundle = mNavigatorStateToRestore.getBundle(name);
if (bundle != null) {
navigator.onRestoreState(bundle);
}
}
}
}
// 这里都是 栈状态的更新 保存 等处理,
if (mBackStackToRestore != null) {
for (Parcelable parcelable : mBackStackToRestore) {
NavBackStackEntryState state = (NavBackStackEntryState) parcelable;
NavDestination node = findDestination(state.getDestinationId());
if (node == null) {
final String dest = NavDestination.getDisplayName(mContext,
state.getDestinationId());
throw new IllegalStateException("Restoring the Navigation back stack failed:"
+ " destination " + dest
+ " cannot be found from the current destination "
+ getCurrentDestination());
}
Bundle args = state.getArgs();
if (args != null) {
args.setClassLoader(mContext.getClassLoader());
}
NavBackStackEntry entry = new NavBackStackEntry(mContext, node, args,
mLifecycleOwner, mViewModel,
state.getUUID(), state.getSavedState());
mBackStack.add(entry);
}
updateOnBackPressedCallbackEnabled();
mBackStackToRestore = null;
}
// 此代码就比较关键了,如果 前面辛辛苦苦保存的mGraph对象不为空,并且,栈里面是空的 取不出来的情况下,
if (mGraph != null && mBackStack.isEmpty()) {
boolean deepLinked = !mDeepLinkHandled && mActivity != null
&& handleDeepLink(mActivity.getIntent());
if (!deepLinked) {
// 这里说的很清楚了,导航到图表中的第一个目的地
navigate(mGraph, startDestinationArgs, null, null);
}
} else {
dispatchOnDestinationChanged();
}
}
方法NavController#navigation
是导航目的地
private void navigate(@NonNull NavDestination node, @Nullable Bundle args,
@Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
boolean popped = false;
boolean launchSingleTop = false;
if (navOptions != null) {
if (navOptions.getPopUpTo() != -1) {
popped = popBackStackInternal(navOptions.getPopUpTo(),
navOptions.isPopUpToInclusive());
}
}
// 同学们注意:这里是关键,真正的导航过程了
Navigator<NavDestination> navigator = mNavigatorProvider.getNavigator(node.getNavigatorName());
// 导航需要的参数集
Bundle finalArgs = node.addInDefaultArgs(args);
// 构建新的目的地对象,此对象,就是后续要完成的目标了
NavDestination newDest = navigator.navigate(node, finalArgs,
navOptions, navigatorExtras);
if (newDest != null) {
if (!(newDest instanceof FloatingWindow)) {
while (!mBackStack.isEmpty()
&& mBackStack.peekLast().getDestination() instanceof FloatingWindow
&& popBackStackInternal(
mBackStack.peekLast().getDestination().getId(), true)) {
// Keep popping
}
}
ArrayDeque<NavBackStackEntry> hierarchy = new ArrayDeque<>();
NavDestination destination = newDest;
if (node instanceof NavGraph) {
do {
NavGraph parent = destination.getParent();
if (parent != null) {
NavBackStackEntry entry = new NavBackStackEntry(mContext, parent,
finalArgs, mLifecycleOwner, mViewModel);
hierarchy.addFirst(entry);
// Pop any orphaned copy of that navigation graph off the back stack
if (!mBackStack.isEmpty()
&& mBackStack.getLast().getDestination() == parent) {
popBackStackInternal(parent.getId(), true);
}
}
destination = parent;
} while (destination != null && destination != node);
}
// Now collect the set of all intermediate NavGraphs that need to be put onto
// the back stack
destination = hierarchy.isEmpty()
? newDest
: hierarchy.getFirst().getDestination();
while (destination != null && findDestination(destination.getId()) == null) {
NavGraph parent = destination.getParent();
if (parent != null) {
NavBackStackEntry entry = new NavBackStackEntry(mContext, parent, finalArgs,
mLifecycleOwner, mViewModel);
hierarchy.addFirst(entry);
}
destination = parent;
}
NavDestination overlappingDestination = hierarchy.isEmpty()
? newDest
: hierarchy.getLast().getDestination();
// Pop any orphaned navigation graphs that don't connect to the new destinations
//noinspection StatementWithEmptyBody
while (!mBackStack.isEmpty()
&& mBackStack.getLast().getDestination() instanceof NavGraph
&& ((NavGraph) mBackStack.getLast().getDestination()).findNode(
overlappingDestination.getId(), false) == null
&& popBackStackInternal(mBackStack.getLast().getDestination().getId(), true)) {
// Keep popping
}
mBackStack.addAll(hierarchy);
// The mGraph should always be on the back stack after you navigate()
if (mBackStack.isEmpty() || mBackStack.getFirst().getDestination() != mGraph) {
NavBackStackEntry entry = new NavBackStackEntry(mContext, mGraph, finalArgs,
mLifecycleOwner, mViewModel);
mBackStack.addFirst(entry);
}
// And finally, add the new destination with its default args
NavBackStackEntry newBackStackEntry = new NavBackStackEntry(mContext, newDest,
newDest.addInDefaultArgs(finalArgs), mLifecycleOwner, mViewModel);
mBackStack.add(newBackStackEntry);
} else if (navOptions != null && navOptions.shouldLaunchSingleTop()) {
launchSingleTop = true;
NavBackStackEntry singleTopBackStackEntry = mBackStack.peekLast();
if (singleTopBackStackEntry != null) {
singleTopBackStackEntry.replaceArguments(finalArgs);
}
}
updateOnBackPressedCallbackEnabled();
if (popped || newDest != null || launchSingleTop) {
dispatchOnDestinationChanged();
}
}
七、NavInflater 导航资源加载类
public final class NavInflater {
private static final String TAG_ARGUMENT = "argument";
private static final String TAG_DEEP_LINK = "deepLink";
private static final String TAG_ACTION = "action";
private static final String TAG_INCLUDE = "include";
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final String APPLICATION_ID_PLACEHOLDER = "${applicationId}";
private static final ThreadLocal<TypedValue> sTmpValue = new ThreadLocal<>();
private Context mContext;
private NavigatorProvider mNavigatorProvider;
public NavInflater(@NonNull Context context, @NonNull NavigatorProvider navigatorProvider) {
mContext = context;
mNavigatorProvider = navigatorProvider;
}
//解析资源 xml
public NavGraph inflate(@NavigationRes int graphResId) {
Resources res = mContext.getResources();
//获取 xml 文件
XmlResourceParser parser = res.getXml(graphResId);
//获取属性
final AttributeSet attrs = Xml.asAttributeSet(parser);
try {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
// Empty loop
}
if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException("No start tag found");
}
String rootElement = parser.getName();
// 解析时,主要是把目的地获取到了
NavDestination destination = inflate(res, parser, attrs, graphResId);
if (!(destination instanceof NavGraph)) {
throw new IllegalArgumentException("Root element <" + rootElement + ">"
+ " did not inflate into a NavGraph");
}
// 返回要导航的 目的地
return (NavGraph) destination;
} catch (Exception e) {
throw new RuntimeException("Exception inflating "
+ res.getResourceName(graphResId) + " line "
+ parser.getLineNumber(), e);
} finally {
parser.close();
}
}
private NavDestination inflate(@NonNull Resources res, @NonNull XmlResourceParser parser,
@NonNull AttributeSet attrs, int graphResId)
throws XmlPullParserException, IOException {
//获取导航
Navigator<?> navigator = mNavigatorProvider.getNavigator(parser.getName());
//在 Navigator 的实现类中创建对应的导航目的
final NavDestination dest = navigator.createDestination();
//解析对应导航的资源
dest.onInflate(mContext, attrs);
final int innerDepth = parser.getDepth() + 1;
int type;
int depth;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& ((depth = parser.getDepth()) >= innerDepth
|| type != XmlPullParser.END_TAG)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
if (depth > innerDepth) {
continue;
}
final String name = parser.getName();
if (TAG_ARGUMENT.equals(name)) {
inflateArgumentForDestination(res, dest, attrs, graphResId);
} else if (TAG_DEEP_LINK.equals(name)) {
inflateDeepLink(res, dest, attrs);
} else if (TAG_ACTION.equals(name)) {
inflateAction(res, dest, attrs, parser, graphResId);
} else if (TAG_INCLUDE.equals(name) && dest instanceof NavGraph) {
final TypedArray a = res.obtainAttributes(
attrs, androidx.navigation.R.styleable.NavInclude);
final int id = a.getResourceId(
androidx.navigation.R.styleable.NavInclude_graph, 0);
((NavGraph) dest).addDestination(inflate(id));
a.recycle();
} else if (dest instanceof NavGraph) {
((NavGraph) dest).addDestination(inflate(res, parser, attrs, graphResId));
}
}
return dest;
}
}
执行NavGraph#addDestination
保存导航
public class NavGraph extends NavDestination implements Iterable<NavDestination> {
//保存Destination
final SparseArrayCompat<NavDestination> mNodes = new SparseArrayCompat<>();
private int mStartDestId;
private String mStartDestIdName;
public final void addDestinations(@NonNull Collection<NavDestination> nodes) {
for (NavDestination node : nodes) {
if (node == null) {
continue;
}
addDestination(node);
}
}
public final void addDestinations(@NonNull NavDestination... nodes) {
for (NavDestination node : nodes) {
if (node == null) {
continue;
}
addDestination(node);
}
}
public final void addDestination(@NonNull NavDestination node) {
//获取节点 id
int id = node.getId();
if (id == 0) {
throw new IllegalArgumentException("Destinations must have an id."
+ " Call setId() or include an android:id in your navigation XML.");
}
if (id == getId()) {
throw new IllegalArgumentException("Destination " + node + " cannot have the same id "
+ "as graph " + this);
}
//根据 id 获取节点
NavDestination existingDestination = mNodes.get(id);
//同一个节点,直接返回
if (existingDestination == node) {
return;
}
if (node.getParent() != null) {
throw new IllegalStateException("Destination already has a parent set."
+ " Call NavGraph.remove() to remove the previous parent.");
}
if (existingDestination != null) {
existingDestination.setParent(null);
}
node.setParent(this);
//保存节点
mNodes.put(node.getId(), node);
}
public final NavDestination findNode(@IdRes int resid) {
return findNode(resid, true);
}
//根据 id 查找节点
final NavDestination findNode(@IdRes int resid, boolean searchParents) {
NavDestination destination = mNodes.get(resid);
// 返回对应的节点
return destination != null
? destination
: searchParents && getParent() != null ? getParent().findNode(resid) : null;
}
}