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
-
工程结构:
-
代码实现:
-
MainPage1Fragment
-
MainPage2Fragment
-
MainPage3Fragment
-
-
-
构建Navgation导航图:nav_gragh_main.xml
-
原始res目录
-
选中res--->右键--->New--->Android Resource File
-
type选择Navigation(会在res文件夹下自动新建一个navigation文件夹,存放新建 .xml)
-
新建后的res资源目录
-
-
建立导航图与Fragment之间的链接
-
点击nav_graph_main.xml--->Design
-
修改默认启动项:
-
代码修改:
-
-
通过拖动建立Fragment之间的跳转关系(指定action)
-
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
-
-
代码展示:
-
-
Activity:
-
绑定导航栏
-
实现效果:
-
实现细节:
-
别名问题:action也有自己的id,它包含的page又有单独的id;可以实现调用action的id拿到指定的Page的id,再跳转到指定的page
-
系统返回键:按照Back的时候,会调用这句话
-
实际上在创建Activity的时候,就可以选择ButtomNavigationActivity
-
三个Fragment,一个对应一个ViewModel
-
在Activity中引入主导航(必须的)
-
组件在高版本中会遇到很多问题:
-
先改版本,
-
在加属性修饰exported
-
这个是Mutable搞的
-
-
-
-
-
Navigation源码分析
-
有一张很大的图
-
MainActivity去绑定Navigation(官网的说法)?实际上不是这样的
-
会搞一个Fragment(主导航)黏贴到Activity上面去
-
-
create函数:实例化主导航栏
- 这个最开始,官网上是明确写出了会调用这个函数;但是后面搞成隐式调用了
-
Create函数:拿到主导航布局文件(graphId)
-
create函数:
- Bundle:保存一下;
- 进行主导航栏实例化
-
onInflate函数:在解析nav_graph_main.xml文件时会调用解析器
-
去解析导航图:拿到activity_main.xml中的两个属性
-
-
初始化(容器)工作:NavigatorProvider(HashMap中保存导航图中所涉及的所有Fragment的信息)
-
图示
进入NavigatorProvider:
看到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)
-
功能:
-
实例化控制器:
-
大量容错代码(因为这个是一个if,可进可不进)
-
布局解析成功:graphId!=0
-
调用Android原生解析器解析布局
-
-
Android Studio 一直卡在 Analyzing...
修改kotlin插件版本,以及gradle版本即可