为了避免歧义,本文所引用的Navigation版本为:2.3.2,Navigation的官网文档地址为:Navigation 组件使用入门
def nav_version = "2.3.2"
// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
本文试图为读者搭建出Navigation库的内部导航过程,以一个Activity和多个Fragment组成的功能页面来作为分析的对象,这里多说一句,看源码有一个技巧,就是所谓“抓大放小”,抓住主要流程,忽略次要部分,这样才不会被淹没在源码的海洋里。
NavHostFragment(导航宿主Fragment)
一般在使用NavHostFragment时是在Activity的布局文件中进行配置,如下:
<androidx.fragment.app.FragmentContainerView
android:id="@+id/my_nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="9"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph_main"/>
我们进入NavHostFragment内部查看其源码,首先,它继承自Fragment,实现了NavHost接口
public class NavHostFragment extends Fragment implements NavHost {
}
代码执行到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);
final int graphId = navHost.getResourceId(
androidx.navigation.R.styleable.NavHost_navGraph, 0);
if (graphId != 0) {
mGraphId = graphId;//解析出导航图ID
}
navHost.recycle();
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NavHostFragment);
final boolean defaultHost = a.getBoolean(R.styleable.NavHostFragment_defaultNavHost, false);
if (defaultHost) {
mDefaultNavHost = true;//解析出标示是否是默认导航宿主
}
a.recycle();
}
本方法有2个目的。
目的1、解析出导航图ID:mGraphId,其对应的配置属性为:
app:navGraph="@navigation/nav_graph_main"
mGraphId解析出来的值为:@navigation/nav_graph_main,是导航图的真实路径。
目的2、解析出标示是否是默认导航宿主的属性mDefaultNavHost,对应的配置信息是:
app:defaultNavHost="true"
接下来,代码会执行到NavHostFragment生命周期的
- onCreate()
public void onCreate(@Nullable Bundle savedInstanceState) {
final Context context = requireContext();
mNavController = new NavHostController(context);//1
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);//2
Bundle navState = null;
......
if (mGraphId != 0) {
// Set from onInflate()
mNavController.setGraph(mGraphId);//3
} 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);
}
}
......
}
本方法创建了NavHostController的对象mNavController,并设置了一系列属性,在注释代码1处,我们进入
- NavHostController