Navigation基础

572 阅读3分钟

2022.1.5 Navigation源码解析

  • 巴拉巴拉:

    • JetPack组件库共有差不多60个库

    • Android应该只有一个Activity:

      • Navigation的初心
      • 一个Activity作为控制层,有许多Fragment显示页面(对比前端的脚手架)
  • Navigation概述:

    • 主要功能:完成Fragment的导航

    • 实现思路:

      • MainActivity--->activity_main.xml(NavHostFragment)--->navigation包(nav_xml)这个里面就有许多Fragment了

      • 每一个Fragment有各自的fragment.xml以及各自的FragmentViewModel(这个来维护)

      • 从Nav包中对应各自的Fragment处理FragmentViewModel

      • 但是仓库是唯一的

      • 此时Activity就是控制者了,

代码实现:

  • 构建MainActivity与Fragment

    • 工程结构:

      image-20220105142241961

    • 代码实现:

      • MainPage1Fragment

        image-20220105142409979

      • MainPage2Fragment

        image-20220105142443729

      • MainPage3Fragment

        image-20220105142517111

  • 构建Navgation导航图:nav_gragh_main.xml

    • 原始res目录

      image-20220105142821850

    • 选中res--->右键--->New--->Android Resource File

      image-20220105142916010

    • type选择Navigation(会在res文件夹下自动新建一个navigation文件夹,存放新建 .xml)

      image-20220105143129443

    • 新建后的res资源目录

      image-20220105143336469

  • 建立导航图与Fragment之间的链接

    • 点击nav_graph_main.xml--->Design

      image-20220105145456109

    • 修改默认启动项:

      • 代码修改:

        image-20220105145632183

    • 通过拖动建立Fragment之间的跳转关系(指定action)

      image-20220105145818482

    • nav_graph_main.xml

       <?xml version="1.0" encoding="utf-8"?>
       <navigation xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:app="http://schemas.android.com/apk/res-auto"
           xmlns:tools="http://schemas.android.com/tools"
           android:id="@+id/nav_graph_main.xml"
           app:startDestination="@id/page1Fragment">
       ​
       ​
           <!-- TODO 同学们 这个是第一个 Fragment -->
           <fragment
               android:id="@+id/page1Fragment"
               android:name="com.derry.navigation.MainPage1Fragment"反射实例化
               android:label="fragment_page1"
               tools:layout="@layout/fragment_main_page1">
               <!--
                   action:程序中使用id跳到destination对应的类
               -->
               <action
                   android:id="@+id/action_page2"
                   app:destination="@id/page2Fragment" />
           </fragment>
       ​
       ​
           <!-- TODO 同学们 这个是第二个 Fragment -->
           <fragment
               android:id="@+id/page2Fragment"
               android:name="com.derry.navigation.MainPage2Fragment"
               android:label="fragment_page2"
               tools:layout="@layout/fragment_main_page2">
               <action
                   android:id="@+id/action_page1"
                   app:destination="@id/page1Fragment" />
               <action
                   android:id="@+id/action_page3"
                   app:destination="@id/page3Fragment" />
           </fragment>
       ​
       ​
           <!-- TODO 同学们 这个是第三个 Fragment -->
           <!--    <navigation-->
           <!--        android:id="@+id/nav_graph_page3"-->
           <!--        app:startDestination="@id/page3Fragment">-->
           <fragment
               android:id="@+id/page3Fragment"
               android:name="com.derry.navigation.MainPage3Fragment"
               android:label="fragment_page3"
               tools:layout="@layout/fragment_main_page3">
               <action
                   android:id="@+id/action_page2"
                   app:destination="@id/page2Fragment" />
           </fragment>
       ​
       </navigation>
      
  • 编写Activity代码:控制导航图实现对Fragment的控制(这个导航图是很流行的)

    • xml:

      • 实现细节:

        • 引入NavHostFragment(内部会包装一下,拿给Fragment进行管理)

        • defaultNavHost = “true”:拦截系统返回键(屏蔽系统内置Fragment栈)

        • app:navGraph="@navigation/nav_graph_main":激活导航图,显示默认Fragment

        • 添加底部导航栏:依托menu

          image-20220105154624671

      • 代码展示:

        image-20220105154540886

    • Activity:

      • 绑定导航栏

        image-20220105155828557

      • 实现效果:

        image-20220105160752456

      • 实现细节:

        • 别名问题:action也有自己的id,它包含的page又有单独的id;可以实现调用action的id拿到指定的Page的id,再跳转到指定的page

          image-20220105160111298

        • 系统返回键:按照Back的时候,会调用这句话

          image-20220105160222631

        • 实际上在创建Activity的时候,就可以选择ButtomNavigationActivity

          • 三个Fragment,一个对应一个ViewModel

          • 在Activity中引入主导航(必须的)

          • 组件在高版本中会遇到很多问题:

            • 先改版本,

            • 在加属性修饰exported

            • 这个是Mutable搞的

Navigation源码分析

  • 有一张很大的图

  • MainActivity去绑定Navigation(官网的说法)?实际上不是这样的

    • 会搞一个Fragment(主导航)黏贴到Activity上面去

      image-20220105201149959

  • create函数:实例化主导航栏

    • 这个最开始,官网上是明确写出了会调用这个函数;但是后面搞成隐式调用了
    • Create函数:拿到主导航布局文件(graphId)

      image-20220105201438116

    • create函数:

      • Bundle:保存一下;
      • 进行主导航栏实例化

      image-20220105201547185

  • onInflate函数:在解析nav_graph_main.xml文件时会调用解析器

    • 去解析导航图:拿到activity_main.xml中的两个属性

      image-20220105202530645

  • 初始化(容器)工作:NavigatorProvider(HashMap中保存导航图中所涉及的所有Fragment的信息)

    • 图示

      image-20220105203248544

      进入NavigatorProvider:

      image-20220105203332250

      看到HashMap:存储Navigation中所涉及的Fragment

    • 这里面有一个细节:getContainerId:不写xml的时候,写java代码才有用;

    • 通过NavInflater布局解析器最终会从graph布局解析出一个NavGraph对象

      • 这个对象拥有所有的graph导航的信息集合
      • 以后操作此对象,就可以操作导航信息了
    • NavHostFragment:只是临时存放一页Fragment

    • 在NavController中会保存:

      • mGraphId
      • mBackStackDequeue
      • mNavigationProvider
      • navigation
  • 调用顺序:navigation--->NavDestination(中转站)--->Navigator(具体执行跳转的类)--->具体的跳转子类;类的描述是没有解决的

  • NavDestination:只做中转站,为了更好的体现出扩展性,单一职责原则

    • FragmentNavigatorDestination

    • ActivityNavigatorDestination

      • 使用startActivity进行跳转
  • Navigator:决定跳转到哪里

    • ActivityNavigator
    • FragmentNavigator
  • 为什么要搞这么多的中间层?

    • 设计定律:任何高耦合,低扩展问题都可以搞一个中间层进行解决;

      • 达到低耦合的效果
    • 中间层衍生出:订阅模式,装饰者模式

生命周期函数

  • onCreate():public void onCreate(@Nullable Bundle savedInstanceState)

    • 功能:

      • 实例化控制器:

        image-20220105210305944

      • 大量容错代码(因为这个是一个if,可进可不进)

      • 布局解析成功:graphId!=0

        image-20220105210359461

      • 调用Android原生解析器解析布局

        image-20220105210558923

Android Studio 一直卡在 Analyzing...

www.jianshu.com/p/79ced5c3b…

修改kotlin插件版本,以及gradle版本即可

image-20220105200636753