Android Jetpack之Navigation源码分析

Android Navigation简介

关于Fragment的基础篇:Fragment基础篇
官方指导地址:官方指地址
Github demo 地址:demo
使用Navigation可以管理APP页面跳转。Navigation不部分情况下作用于Fragment中,使用Navigation切换Fragment可以使代码简洁,直观。Navigation导航组件还支持:Fragment、Activity、导航图和子图、自定义目标等。

Navigation的使用

基础使用

  1. 添加项目组件依赖
 def nav_dep = "2.0.0"   implementation "androidx.navigation:navigation-fragment:$nav_dep" implementation "androidx.navigation:navigation-ui:$nav_dep"
  1. 导航文件XML
    在module下的res目录下,新建navigation文件夹,然后在navigation文件夹下新建一个navigation的xml文件:navigation_jetpack.xml
<?xml version="1.0" encoding="utf-8"?>                                                                

字段解析:
(1)navigation根节点 startDestination 表示第一个显示的fragment。即FirstNavigationFragment
(2)fragment 节点中name属性表示所属的fragment类
(3)fragment 节点中action节点destination属性用于指定下一个目标fragment
(4)fragment 节点中argument 用于传递数据。表示的是传递到当前Fragment的数据,Key为name属性,默认数据是android:defaultValue,数据类型是argType。
3. 创建Fragment
以ThirdNavigationFragment为例。onCreateView返回布局View。onViewCreated设置点击时间,执行相应的action,来完成Fragment的跳转。在页面跳欢时,会执行onDestroyView方法,从新回到该Fragment,会执行方法onCreateView方法。

class ThirdNavigationFragment : Fragment(){    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {        return LayoutInflater.from(this.activity).inflate(R.layout.fragment_third_navigation,container,false)    }    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {        super.onViewCreated(view, savedInstanceState)        btn_third_fragment.setOnClickListener{            Navigation.findNavController(it).navigate(R.id.action_popup_to_first_fragment_from_third)        }    }}
  1. 创建Activity
    4.1 activity布局文件。
<?xml version="1.0" encoding="utf-8"?>                

布局解析:
(1)xml实现和代码实现在使用时,请务必注解其中一个。
(2)如果使用xml实现,fragment务必设置id。navGraph 用来表示上面的导航意图文件 navigation_jetpack.xml
(3)name 必须指定为以下值,这是切换fragment的容器
android:name=“androidx.navigation.fragment.NavHostFragment”
(4)defaultNavHost 表示是否拦截返回键,默认为false。
4.2 Activity中使用
如果使用的是代码实现的布局文件,在Activity中使用如下代码:
(1)初始化NavHostFragment。
(2)将NavHostFragment绑定到布局文件的FrameLayout中。

class NavigationActivity : AppCompatActivity(){    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_navigation)        val finalHost = NavHostFragment.create(R.navigation.navigation_jetpack)        supportFragmentManager.beginTransaction()            .replace(R.id.ll_fragment_navigation, finalHost)            .setPrimaryNavigationFragment(finalHost)            .commit()    }}
  1. 切换fragment

切换Fragment主要有一下两种方式:
(1)方式1:

Navigation.findNavController(it).navigate(R.id.action_to_second_fragment)

(2)方式2:

NavHostFragment.findNavController(this).navigate(R.id.action_to_second_fragment,null)

这两种实现方式其实都返回了一个 NavController 类,然后再通过调用navigate方法控制页面导航,也就是说通过NavController 我们可以控制所有的Fragment导航行为。
7. 数据传递
在navigation导航文件中可以通过设置argument标签,来设置fragment所接收的参数类型和默认值。

 

或者在代码中使用传统方式:

 val bundle = Bundle() bundle.putString("name","Blank") bundle.putInt("number",10) NavHostFragment.findNavController(this).navigate(R.id.action_to_second_fragment,bundle)

在代码中,使用navigate() 方法并将Bundle并将其传递到目标。接受方Fragment中,使用getArguments()方法检索包并使用其内容。
8. 嵌套导航图
可以将目的地分组为导航图中的子图,子图也被称为“ 嵌套图 ”,包含图称为“ 根图“。如下我们建立子图:third_navigation。

<?xml version="1.0" encoding="utf-8"?>                                                                                    
  1. include引用其他图形
    使用include引用其他图形
    比如我们建立视图:navigation_nested.xml 布局文件如下:
<?xml version="1.0" encoding="utf-8"?>                

在navigation_jetpack中include navigation_nested。

<?xml version="1.0" encoding="utf-8"?>                                                    
  1. 其他用法

Navigation的其他用法可以参考下面Blog,包含Deep Link等。

https://cloud.tencent.com/developer/article/1446342

https://blog.csdn.net/lyhhj/article/details/93757755

https://cloud.tencent.com/developer/article/1452921

源码分析

3.1 构建NavController

通过上面的Navigation使用,我们知道NavHostFragment作为一个容器,所有的导航操作都是NavHostFragment中进行,在NavHostFragment中又委托给了NavController类。所以我们下面主要看看NavController类是如何被创建出来的,以及在创建过程中NavHostFragment类都做那些初始化工作。NavHostFragment的初始化主要有两种实现方式,1:配置XML文件。2:代码实现。下面我们以代码实现NavHostFragment.create为入口来分析,NavHostFragment类。

  val finalHost = NavHostFragment.create(R.navigation.navigation_jetpack)        supportFragmentManager.beginTransaction()            .replace(R.id.ll_fragment_navigation, finalHost)            .setPrimaryNavigationFragment(finalHost)            .commit()
  1. NavHostFragment.create方法
    (1)初始化Bundle,并且将graphResId,startDestinationArgs存储在Bundle中。
    (2)返回NavHostFragment实例。
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);        }        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;    }
  1. NavHostFragment.onInflate方法
    当Fragment以XML的方式静态加载时,最先会调用onInflate的方法(调用时机:Fragment所关联的Activity在执行setContentView时)。
    (1)主要是解析布局文件的两个属性。defaultNavHost和navGraph,并且初始化全局变量
    (1)defaltNavHost为true时,NavHostFragment将会通过FragmentManager 切换到回退栈顶部,并且可以拦截返回键事件(back事件)。
public void onInflate(@NonNull Context context, @NonNull AttributeSet attrs,            @Nullable Bundle savedInstanceState) {        super.onInflate(context, attrs, savedInstanceState);        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NavHostFragment);        final int graphId = a.getResourceId(R.styleable.NavHostFragment_navGraph, 0);        final boolean defaultHost = a.getBoolean(R.styleable.NavHostFragment_defaultNavHost, false);        if (graphId != 0) {            mGraphId = graphId;        }        if (defaultHost) {            mDefaultNavHost = true;        }        a.recycle();    }
  1. NavHostFragment.onCreate方法。无论是XML实现还是代码实现,都会执行Fragment的onCreate方法,可谓是殊途同归。NavController在这里被创建,并且NavHostFragment中有一个NavController对象。
    (1)初始化NavController,NavController为导航的控制类,核心类。
    (2)在SimpleNavigatorProvider中以键值对保存FragmentNavigator类。该类之后会做介绍。
    (3)savedInstanceState不为空时候,恢复controller的状态
    (4)将graph设置给navController,构建NavGraph。下面会单独分析该模块。
    (5)当defaltNavHost为true,将会被设置为主导航fragment。可以拦截返回键事件(back事件)。
    (6)通过addNavigator添加FragmentNavigator,下面会分析到。
public void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        final Context context = requireContext();        mNavController = new NavController(context);        mNavController.getNavigatorProvider().addNavigator(createFragmentNavigator());        Bundle navState = null;        if (savedInstanceState != null) {            navState = savedInstanceState.getBundle(KEY_NAV_CONTROLLER_STATE);            if (savedInstanceState.getBoolean(KEY_DEFAULT_NAV_HOST, false)) {                mDefaultNavHost = true;                requireFragmentManager().beginTransaction()                        .setPrimaryNavigationFragment(this)                        .commit();            }        }        if (navState != null) {            // Navigation controller state overrides arguments            mNavController.restoreState(navState);        }        if (mGraphId != 0) {            // Set from onInflate()            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);            }        }    }
  1. NavController.onCreateView方法
    该NavHostFragment的视图就只有一个FrameLayout布局, 在NavHostFragment的创建时,为它创建一个FrameLayout作为导航界面的载体。
 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,                             @Nullable Bundle savedInstanceState) {        FrameLayout frameLayout = new FrameLayout(inflater.getContext());        // When added via XML, this has no effect (since this FrameLayout is given the ID        // automatically), but this ensures that the View exists as part of this Fragment's View        // hierarchy in cases where the NavHostFragment is added programmatically as is required        // for child fragment transactions        frameLayout.setId(getId());        return frameLayout;    }
  1. NavController.onViewCreated
    (1)当通过XML添加时,父View是null,我们的view就是NavHostFragment的根。
    (2)但是当以代码方式添加时,需要在父级上设置NavController。
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");        }        // When added via XML, the parent is null and our view is the root of the NavHostFragment        // but when added programmatically, we need to set the NavController on the parent - i.e.,        // the View that has the ID matching this NavHostFragment.        View rootView = view.getParent() != null ? (View) view.getParent() : view;        Navigation.setViewNavController(rootView, mNavController);    }
  1. Navigation.setViewNavController方法。
    主要是将NavController对象设置为rootView的tag。方便以后递归遍历到NavController对象,确保NavController对象的唯一。
  public static void setViewNavController(@NonNull View view,            @Nullable NavController controller) {        view.setTag(R.id.nav_controller_view_tag, controller);    }

至此整个NavController对象和NavHostFragment的关系我们已经梳理明白了。下面来看看
NavController是如何参与到导航事件的。

3.2 获取NavController

要想NavController参与到导航事件,必须获取到该对象才可以。在Fragment 中控制导航的时候,上面介绍了两种实现方式。
(1)Navigation.findNavController(it).navigate(R.id.action_page)
(2)NavHostFragment.findNavController(this).navigate(R.id.action)
其实无论是通过findNavController或者是findNavController返回的都是NavController对象。
在构建NavController对象的时候,我们使用到了Navigation类,下面就从该类分析。findNavController方法形参是个View对象,所以是通过view就去查找就NavController,还记得上面用到的viewRoot吗?。

  1. findNavController方法
    该方法没什么实质性的代码,只要是调用了findViewNavController方法。
   public static NavController findNavController(@NonNull View view) {        NavController navController = findViewNavController(view);        if (navController == null) {            throw new IllegalStateException("View " + view + " does not have a NavController set");        }        return navController;    }
  1. findViewNavController方法
    通过view递归循环查找NavController。内部调用了getViewNavController方法。
 private static NavController findViewNavController(@NonNull View view) {        while (view != null) {            NavController controller = getViewNavController(view);            if (controller != null) {                return controller;            }            ViewParent parent = view.getParent();            view = parent instanceof View ? (View) parent : null;        }        return null;    }
  1. getViewNavController方法
    通过获取view的Tag,获取NavController对象,这里的tag ID和setViewNavController都是nav_controller_view_tag。
private static NavController getViewNavController(@NonNull View view) {        Object tag = view.getTag(R.id.nav_controller_view_tag);        NavController controller = null;        if (tag instanceof WeakReference) {            controller = ((WeakReference) tag).get();        } else if (tag instanceof NavController) {            controller = (NavController) tag;        }        return controller;    }

至此NavController的获取过程已经分析完毕。

4 真正的导航实现

在实现导航的时候,我们需要根据navigation配置文件生成NavGraph类,然后在根据每个不同的action id,找到对应的NavDestination就可以实现页面导航跳转了。

4.1 构建NavGraph

  1. SimpleNavigatorProvider类
    在构建NavController的时候,在onCreate方法中调用了如下代码。
  mNavController = new NavController(context);  mNavController.getNavigatorProvider().addNavigator(createFragmentNavigator());

(1)其中mNavigatorProvider是NavController中的全局变量,内部通过HashMap键值对的形式保存Navigator类。

private final NavigatorProvider mNavigatorProvider = new NavigatorProvider() {        @Nullable        @Override        public Navigator<? extends NavDestination> addNavigator(@NonNull String name,                @NonNull Navigator<? extends NavDestination> navigator) {            Navigator<? extends NavDestination> previousNavigator =                    super.addNavigator(name, navigator);            if (previousNavigator != navigator) {                if (previousNavigator != null) {                    previousNavigator.removeOnNavigatorBackPressListener(mOnBackPressListener);                }                navigator.addOnNavigatorBackPressListener(mOnBackPressListener);            }            return previousNavigator;        }    };

(2)createFragmentNavigator方法,构建了FragmentNavigator对象,其中抽象类Navigator还有个重要的实现类ActivityNavigator和NavGraphNavigator。这个两个类的对象在NavController的构造方法中被添加。。

public class FragmentNavigator extends Navigator 

(3)其中Navigator类的作用是:能够实例化对应的NavDestination,并且能够实现导航功能,拥有自己的回退栈。
2. 构建NavGraph
在构建NavController的时候,我们还调用了NavController.setGraph(graphId)方法,该方法主要是构建NavGraph。
(1)调用getNavInflater方法创建NavInflater对象,用于解析navigation xml文件

  public void setGraph(@NavigationRes int graphResId, @Nullable Bundle startDestinationArgs) {        setGraph(getNavInflater().inflate(graphResId), startDestinationArgs);    }

(2) NavInflater.inflate方法
根据传入的XML资源id构建NavGraph,NavGraph组成Fragment路由的导航地图,而NavDestination代表了导航的每一个目的地。在解析完NavDestination后,需要要求NavDestination为NavGraph,即NavGraph是NavDestination的子类。而且在NavGraph内部存储了NavDestination信息。

public NavGraph inflate(@NavigationRes int graphResId) {        Resources res = mContext.getResources();        //拿到XML的解析器        XmlResourceParser parser = res.getXml(graphResId);        final AttributeSet attrs = Xml.asAttributeSet(parser);        try {            String rootElement = parser.getName();            //构建出NavDestination            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();        }    }

上面的inflate方法内部会继续调用inflate方法。
(1)getNavigator方法获取都Navigator实例,该实例在构建NavController是被添加进去,这里获取的是FragmentNavigator对象。
(2)createDestination方法,会调用FragmentNavigator的createDestination构建Destination对象。
(3)onInflate方法,调用FragmentNavigator.Destination的方法获取设置的Fragment的类名。
(4)while循环内部通过递归构建导航图。

private NavDestination inflate(Resources res, XmlResourceParser parser, AttributeSet attrs)        throws XmlPullParserException, IOException {    Navigator navigator = mNavigatorProvider.getNavigator(parser.getName());    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)) {            //解析参数,存储在dest中            inflateArgument(res, dest, attrs);        } else if (TAG_DEEP_LINK.equals(name)) {            //解析深度链接            inflateDeepLink(res, dest, attrs);        } else if (TAG_ACTION.equals(name)) {            //解析Action            inflateAction(res, dest, attrs);        } else if (TAG_INCLUDE.equals(name) && dest instanceof NavGraph) {            //如果子节点为graph,加载子节点的destination。即通过include方法。            final TypedArray a = res.obtainAttributes(attrs, R.styleable.NavInclude);            final int id = a.getResourceId(R.styleable.NavInclude_graph, 0);            ((NavGraph) dest).addDestination(inflate(id));            a.recycle();        } else if (dest instanceof NavGraph) {            //如果子节点为graph加载子节点的destination            //向每个NavGraph中加入Destination            ((NavGraph) dest).addDestination(inflate(res, parser, attrs));        }    }    return dest;}
  1. onGraphCreated方法。
    通过NavInflater类之后,解析了XML文件构建整个Graph之后。,下面回到setGraph方法,在解析玩XML后会调用setGraph方法。
    (1)popBackStackInternal方法将旧的导航图全部出栈。
    (2)调用onGraphCreated主要是显示一个导航Fragment视图。
 public void setGraph(@NonNull NavGraph graph, @Nullable Bundle startDestinationArgs) {        if (mGraph != null) {            // Pop everything from the old graph off the back stack            popBackStackInternal(mGraph.getId(), true);        }        mGraph = graph;        onGraphCreated(startDestinationArgs);    }
  1. onGraphCreated方法
    (1)恢复之前的导航状态
    (2)调用navigate方法,显示第一个Fragment。即在Navigation文件里,属性app:startDestination的Fragment。所以最终都会走到navigate导航方法。
 private void onGraphCreated(@Nullable Bundle startDestinationArgs) {        if (mNavigatorStateToRestore != null) {            ArrayList 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 (mBackStackIdsToRestore != null) {            for (int index = 0; index < mBackStackIdsToRestore.length; index++) {                int destinationId = mBackStackIdsToRestore[index];                Bundle args = (Bundle) mBackStackArgsToRestore[index];                NavDestination node = findDestination(destinationId);                if (node == null) {                    throw new IllegalStateException("unknown destination during restore: "                            + mContext.getResources().getResourceName(destinationId));                }                if (args != null) {                    args.setClassLoader(mContext.getClassLoader());                }                mBackStack.add(new NavBackStackEntry(node, args));            }            mBackStackIdsToRestore = null;            mBackStackArgsToRestore = null;        }        if (mGraph != null && mBackStack.isEmpty()) {            boolean deepLinked = mActivity != null && handleDeepLink(mActivity.getIntent());            if (!deepLinked) {                // Navigate to the first destination in the graph                // if we haven't deep linked to a destination                navigate(mGraph, startDestinationArgs, null, null);            }        }    }

导航

在构建和获取到NavController对象以及NavGraph之后。,下面是使用它来实现真正的导航了。下面从navigate开始分析。在navigate方法内部会查询到NavDestination,然后根据不同的Navigator实现页面导航。

  1. navigate 方法
    (1)如果回退栈为null返回NavGraph,不为null返回回退栈中的最后一项。
    (2)根据id,获取对应的NavAction。然后在通过NavAction获取目的地id。
    (4)利用目的地ID属性,通过findDestination方法,找到准备导航的目的地。
    (5)根据导航目的地的名字,调用getNavigator方法,获取Navigator对象。这里对应的是FragmentNavigator。
 public void navigate(@IdRes int resId, @Nullable Bundle args, @Nullable NavOptions navOptions,            @Nullable Navigator.Extras navigatorExtras) {        NavDestination currentNode = mBackStack.isEmpty()                ? mGraph                : mBackStack.getLast().getDestination();        if (currentNode == null) {            throw new IllegalStateException("no current navigation node");        }        @IdRes int destId = resId;        final NavAction navAction = currentNode.getAction(resId);        Bundle combinedArgs = null;        if (navAction != null) {            if (navOptions == null) {                navOptions = navAction.getNavOptions();            }            destId = navAction.getDestinationId();            Bundle navActionArgs = navAction.getDefaultArguments();            if (navActionArgs != null) {                combinedArgs = new Bundle();                combinedArgs.putAll(navActionArgs);            }        }        if (destId == 0 && navOptions != null && navOptions.getPopUpTo() != -1) {            popBackStack(navOptions.getPopUpTo(), navOptions.isPopUpToInclusive());            return;        }        NavDestination node = findDestination(destId);        navigate(node, combinedArgs, navOptions, navigatorExtras);    }private void navigate(@NonNull NavDestination node, @Nullable Bundle args,            @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {        boolean popped = false;        if (navOptions != null) {            if (navOptions.getPopUpTo() != -1) {                popped = popBackStackInternal(navOptions.getPopUpTo(),                        navOptions.isPopUpToInclusive());            }        }        Navigator navigator = mNavigatorProvider.getNavigator(                node.getNavigatorName());        Bundle finalArgs = node.addInDefaultArgs(args);        NavDestination newDest = navigator.navigate(node, finalArgs,                navOptions, navigatorExtras);     
  1. FragmentNavigator的实现
    通过以上的分析,又来到了Navigator 的子类FragmentNavigator类。下面来看看FragmentNavigator.navigate的方法。
    (1)调用instantiateFragment,通过反射机制构建Fragment实例
    (2)处理进出场等动画逻辑
    (3)最终调用FragmentManager来处理导航逻辑。
    猜测ActivityNavigator最终也是调用了startActivity方法,这里就不展示代码了。
 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;        }        String className = destination.getClassName();        if (className.charAt(0) == '.') {            className = mContext.getPackageName() + className;        }        final Fragment frag = instantiateFragment(mContext, mFragmentManager,                className, args);        frag.setArguments(args);        final FragmentTransaction ft = mFragmentManager.beginTransaction();        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);        }        ft.replace(mContainerId, frag);        ft.setPrimaryNavigationFragment(frag);        ft.setReorderingAllowed(true);        ft.commit();    }

小结

(1)NavHostFragment 作为导航载体,在Activity的layout文件里被引用(或者在代码中动态),并且持有导航控制类NavController引用。
(2)NavController 将导航任务委托给Navigator类,Navigator类有两个重要的子类FragmentNavigator和ActivityNavigator子类。NavController类持有NavInflater类引用。
(3)NavInflater 负责解析Navgation文件,负责构建NavGraph导航图。
(4)NavDestination 存有各个目的地信息,在FragmentNavigator和ActivityNavigator内部分别对应一个Destination类,该类继承NavDestination。
(5)在页面导航时,fragment的操作还是交由FragmentManager在操作,activity交由startActivity执行。

下面贴一下,网上总结的比较全的类图信息:
来自图片来源

更多相关文章

  1. Android(安卓)-- Messenger与Service
  2. 【原创】【Android(安卓)Camera】—— 关于FaceDetection
  3. Android(安卓)Launcher3安装应用后,控制应用图标显示位置
  4. Android(安卓)Framework初步认识
  5. android自定义相机添加自定义水印
  6. Android(安卓)事件分发机制(最新源码6.0分析)--ViewGrop
  7. android 自定义view中onMeasure()理解
  8. Android欢迎页面闪屏解决方法
  9. Android进程优先级部分整理与理解

随机推荐

  1. 10个常见的 Android(安卓)新手误区
  2. Android(安卓)Camera 系统框架分析
  3. Android服务器——TomCat服务器的搭建
  4. Android硬件抽象层(HAL)深入剖析(一)
  5. android中shape绘制背景图片
  6. Android(安卓)关于RemoteViews的理解(一)
  7. Android(安卓)之 zygote 与进程创建
  8. 一个让你掌握Android所有控件的Demo
  9. Android(安卓)Layout布局文件里的android
  10. Android程序开发初级教程