Android&Navigation 全面介绍 & 全新的 Fragment 管理器,kotlin 编程通俗演义 pdf
| --- | --- || navigation | 导航或者说回退栈 || graph | 导航图 || destination | 目的地, 即在要跳转的页面 || pop | 出栈, 会一直将destination
出栈, 直到到达指定 id 所在页面, 可以理解为 Fragment 的singleTask
模式 || navHost | 即所有页面的容器. 类似网页中的 host, 所有 path 路径都是在 host 之后跟随, host 固定不变. |
XML

点击 NavResourceFile 中的 Design 即可查看布局编辑器, 布局编辑器分为三栏.
左侧是已添加的导航, 中间是页面浏览, 中间栏的工具栏可以创建和快速添加标签以及整理页面, 右侧属性栏方便添加属性.
navigation
这是个嵌套的图表, 可以点击打开新的图表页面.
Activity 布局中
<LinearLayout.../><androidx.appcompat.widget.Toolbar.../><fragmentandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:id="@+id/my_nav_host_fragment"android:name="androidx.navigation.fragment.NavHostFragment"app:navGraph="@navigation/mobile_navigation"app:defaultNavHost="true"/><com.google.android.material.bottomnavigation.BottomNavigationView.../></LinearLayout>
android:name="androidx.navigation.fragment.NavHostFragment"
固定写法
app:navGraph 指定 navigation 资源文件, 也可以不指定后面通过代码中动态设置
app:defaultNavHost 是否拦截返回键事件, false 表示不需要回退栈.
手写创建 NavHostFragment 时并不会自动代码补全, 可以使用 Editor Designer 创建.

创建资源文件
res 目录创建 AndroidResourceFile 选择 Navigation. 然后 new-> NavigationResourceFile
navigation 节点
app:startDestination="@+id/home_dest" 指定初始目标
navigation 可以嵌套 navigation 标签.在布局编辑器中会显示为:

嵌套 navigation 无法互相关联
<navigationxmlns: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_global
《Android 学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
"app:startDestination="@id/mainFragment">
<fragmentandroid:id="@+id/mainFragment"android:name="com.example.frameexample.MainFragment"android:label="fragment_main"tools:layout="@layout/fragment_main"><actionandroid:id="@+id/action_mainFragment_to_personInfoFragment"app:destination="@id/settingFragment" /></fragment>
<navigationandroid:id="@+id/navigation"app:startDestination="@id/settingFragment"><fragmentandroid:id="@+id/settingFragment"android:name="com.example.frameexample.SettingFragment"android:label="fragment_setting"tools:layout="@layout/fragment_setting" /></navigation>
</navigation>
上面的mainFragment
无法直接app:destination="@id/settingFragment"
这会导致运行错误. 只能先导航到navigation
.(即 NavHostFragment 所在的界面)
fragment 节点
android:id 不言而喻
android:name 目标要实例化的 fragment 完全限定类名
tools:layout 用于显示在布局编辑器
android:label 用于后面绑定 Toolbar 等自动更新标题
argument 节点
android:name="myArg"app:argType="integer"android:defaultValue="0"
参数名称
参数类型
参数默认值
在跳转导航页面的时候会自动在argument
中带上参数(要求指定参数默认值). 数组和Paraclable/Serializable
不支持默认值设置, 通过下面要讲的SafeArg
可以在编译器校验参数类型安全问题.

action 节点
动作 用于页面跳转时指定目标页面
android:id="@+id/next_action"动作 idapp:destination="@+id/flow_step_two_dest">目标页面 app:popUpTo="@id/home_dest"当前属于弹出栈 app:popUpToInclusive="true/false"弹出栈是否包含目标 app:launchSingleTop="true/false"是否开启 singleTop 模式
app:enterAnim=""app:exitAnim=""导航动画
app:popEnterAnim=""app:popExitAnim=""弹出栈动画
如果从导航页面到新的 Activity 页面, 动画不支持. 请使用默认的 Activity 设置动画去支持.
全局动作
NavController 只能使用当前页面在 XMl 中的节点的子节点action
. 不能使用其他的 Fragment 下的动作.
但是可以通过直接给navigation
标签创建子标签action
, 这属于全局动作
, 即每个 Fragment 都能使用的动作.
<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_main"app:startDestination="@id/homeFragment">
<actionandroid:id="@+id/action_categoryFragment_to_main2Activity"app:destination="@id/main2Activity" />
<fragmentandroid:id="@+id/categoryFragment"android:name="com.example.frame.fragment.CategoryFragment"android:label="fragment_category"tools:layout="@layout/fragment_category"/>
</navigation>
占位页

占位页面如果运行时没有指定 Class 并且导航到该占位页面时会抛出异常
总结
一般情况下我们其实只会在 XML 中定义Fragment
节点.
这些action|argument
节点我认为主要是给 SafeArgsGradle 插件使用. 用于给插件扫描自动生成类比较方便, 如果不使用插件我不建议使用者两个节点, 在文章末尾会详细提及如果使用该插件. 该插件主要是自动处理参数的传递和获取以及目的地跳转.
类关系
NavController 控制导航的跳转和弹出栈
NavOptions 控制跳转过程中的配置选项, 例如动画和 singleTop 模式
Navigation 工具类 创建点击事件或者获取控制器 (鸡肋), 自己实现扩展函数可能更加方便.
NavHostFragment 导航的容器, 可以设置和获取导航图(NavGraph)
NavGraph 用于描述导航中页面关系的对象 可以增删改查页面,设置起始页等
NavigationUI 用于将导航和一系列菜单控件自动绑定的工具类
Navigator 页面的根接口, 如果想创建一个新的类型页面就要自定义他
NavigatorProvider 一个内部保存着[名称:Navigator]键值对的 HashMap. 一般情况不需要使用.
NavDeepLinkBuilder 构建一个能打开导航页面的 Intent
NavInflater 用于将 XML 创建成 NavGraph 对象, NavController 可以通过更方便的函数创建不需要直接使用这个类.
void NavInflater(@NonNull Context context,@NonNull NavigatorProvider navigatorProvider) // 要求当前 NavHostFragment 的内部变量// 构造函数, 但一般情况使用 NavController.getNavInflater 获取对象
void NavGraph inflate(@NavigationRes int graphResId)
NavBackStackEntry 表示一个目的地所对应
NavController
NavController 用于跳转页面和参数传递等控制, 可以通过扩展函数得到实例.
通过三个扩展函数可以得到实例
Fragment.findNavController()
View.findNavController()
Activity.findNavController(viewId: Int) // NavHostFragment 的 Id
navigate
跳转目的
public void navigate(@IdRes int resId,@Nullable Bundle args,@Nullable NavOptions navOptions,@Nullable Navigator.Extras navigatorExtras) // 可设置共享元素动画参数
public void navigate(Uri deepLink,NavOptions navOptions,Navigator.Extras navigatorExtras)
除
resId
都是可选参数
通过实现抽象类NavDirections
创建自定义的对象来描述跳转目标(action)和传参(bundle)
public void navigate (NavDirections directions,NavOptions navOptions,Navigator.Extras navigatorExtras)
除
directions
都是可选参数
resId
可以是 XML 中的action
或者destination
节点 id, 如果是 action 则会附带 action 的配置, 如果是 destination 则不会附带 destination 节点下的子节点 action(写了白写).
args
即需要在 fragment 之间传递的 Bundle 参数, 但是导航还支持另外一种插件形式的传递参数方式-安全参数 SafeArgs, 后面提到.
navOptions 即导航页面一些配置选项(例如动画)
返回上级
public boolean navigateUp ()public boolean navigateUp (DrawerLayout drawerLayout)public boolean navigateUp (AppConfiguration appConfiguration)
出栈
弹出栈, 即从 Nav 回退栈中清除 Fragment.
public boolean popBackStack (int destinationId, // 目标 idboolean inclusive) // 是否包含参数目标
public boolean popBackStack ()// 弹出当前 Fragment
目的地变化监听器
每次进行跳转等页面变化时都会回调该监听器
public void addOnDestinationChangedListener (NavController.OnDestinationChangedListener listener)public void removeOnDestinationChangedListener (NavController.OnDestinationChangedListener listener)
public interface OnDestinationChangedListener {/**
导航完成以后回调函数(但是可能动画还在播放中)
@param 控制导航到目标的导航控制器 NavController
@param 目标页面
@param 导航到目标页面的参数*/void onDestinationChanged(@NonNull NavController controller,@NonNull NavDestination destination, @Nullable Bundle arguments);}
DeepLink
NavDeepLinkBuilder createDeepLink ()// 内部就是调用的 DeepLinkBuilder 的构造函数
boolean handleDeepLink(Intent intent)
NavDestination getCurrentDestination ()
NavigatorProvider getNavigatorProvider ()
NavInflater getNavInflater()
Bundle saveState ()void restoreState (Bundle navState)// 用于处理 NavController 的状态获取和恢复
关于 NavGraph 函数
void setGraph(NavGraph graph,Bundle startDestinationArgs);
void setGraph(int graphResId,Bundle startDestinationArgs);
NavGraph getGraph ()
startDestinationArgs
可选参数, 用于传递给起始目的地的参数对象
NavDirections
一个抽象类用于自定义动作和参数, 如果你想复用某个跳转逻辑就可以自定义继承该类. 一般情况下我们并不会手动去继承该类因为过于麻烦, 这个类主要是用于 SafeArgs 插件自动生成的派生类.
Navigator.Extras
前面提到参数 navigatorExtras
目前是用于支持转场动画的共享元素.
通过扩展函数可以快速创建
fun FragmentNavigatorExtras(vararg sharedElements: Pair<View, String>)
fun ActivityNavigatorExtras(activityOptions: ActivityOptionsCompat? = null, flags: Int = 0)
可以从源码看到内部都是使用的 Navigator.Extras.Builder 构造器创建的.
NavOptions
属于导航时的附加选项设置
XML 示例
<fragmentandroid:id="@+id/home_dest"android:name="com.example.android.codelabs.navigation.HomeFragment"android:label="@string/home"tools:layout="@layout/home_fragment">
<actionandroid:id="@+id/next_action"app:destination="@+id/flow_step_one_dest"app:enterAnim="@anim/slide_in_right"app:exitAnim="@anim/slide_out_left"app:popEnterAnim="@anim/slide_in_left"app:popExitAnim="@anim/slide_out_right" />
</fragment>
创建 NavOptions 对象相当于代码动态实现了 XML 中的<action>
标签的属性设置(但是无法指定目标).
目前功能只有设置动画和 singleTop(启动模式), popUp(弹出栈)
创建对象
提供一个 DSL 作用域
fun navOptions(optionsBuilder: NavOptionsBuilder.() -> Unit): NavOptions
示例
val options = navOptions {anim {enter = R.anim.slide_in_right // 进入页面动画 exit = R.anim.slide_out_leftpopEnter = R.anim.slide_in_left // 弹出栈动画 popExit = R.anim.slide_out_right}
launchSingleTop = truepopUpTo = R.id.categoryFragment}
findNavController().navigate(R.id.flow_step_one_dest, null, options)
弹出栈
public NavOptions.Builder setPopUpTo (int destinationId,boolean inclusive)
函数并不会决定目的地, 只是在导航到目的地之前先执行一个弹出栈指令.
场景: 例如我现在购买一个商品支付成功, 这个时候我要将前面的商品详情; 订单配置等页面全部关闭 然后进入<支付成功>页面
顺便说下在之前的做法是发送事件然后 finish
NavDestination
表示当前目标对象
NavController
可以获取NavDestination
findNavController().currentDestination
函数
void addDeepLink(String uriPattern)boolean hasDeepLink(Uri deepLink)
Navigator getNavigator()NavGraph getParent()
NavAction getAction(int id)void putAction(int actionId, NavAction action)void putAction(int actionId, int destId)void removeAction(int actionId)
void setDefaultArguments(Bundle args)void addDefaultArguments(Bundle args)Bundle getDefaultArguments()
void setId(int id)int getId()
void setLabel(CharSequence label)CharSequence getLabel()
NavHostFragment
该对象为 Navigation 提供一个容器
一般使用情况是在布局中直接定义, 但是也可以通过代码构建实例, 然后通过代码创建视图(例如 ViewPager 等)
public static NavHostFragment create (int graphResId)
UI 绑定
Navigation 可以与一系列视图组件进行联动
BottomNavigationView
通过扩展函数可以绑定多个导航图, 且关联 BNV.
fun BottomNavigationView.setupWithNavController(navGraphIds: List<Int>,fragmentManager: FragmentManager,containerId: Int,intent: Intent): LiveData<NavController>
navGraphIds
集合中包含 navGrap 的 Id. 每个 BNV 的按钮对应一个 navGrap.
ActionBar
设置导航到新页面时自动更新标题文字
fun AppCompatActivity.setupActionBarWithNavController(navController: NavController,drawerLayout: DrawerLayout?)
fun AppCompatActivity.setupActionBarWithNavController(navController: NavController,configuration: AppBarConfiguration = AppBarConfiguration(navController.graph))
这里出现个参数 AppBarConfiguration, 用于配置 Toolbar/ActionBar/CollapsingToolbarLayout.
AppBarConfiguration
构造器模式使用 Builder 创建实例
AppBarConfiguration.Builder(NavGraph navGraph)AppBarConfiguration.Builder(Menu topLevelMenu)AppBarConfiguration.Builder(int... topLevelDestinationIds)AppBarConfiguration.Builder(Set<Integer> topLevelDestinationIds)// 构造函数效果等同
函数
AppBarConfiguration.Builder setDrawerLayout(DrawerLayout drawerLayout)// 绑定 Toolbar 同时绑定一个 DrawerLayout 联动
AppBarConfiguration.Builder setFallbackOnNavigateUpListener(AppBarConfiguration.OnNavigateUpListener fallbackOnNavigateUpListener)// 监听返回操作
AppBarConfiguration build()
AppBarConfiguration.OnNavigateUpListener 该回调接口会在每次点击向上导航时回调
public interface OnNavigateUpListener {/**
回调处理向上导航
@return 返回 true 表示向上导航, false 不处理*/boolean onNavigateUp();}
Toolbar
Toolbar 也可以绑定 Nav 自动更新对应页面的标题
源码:
fun Toolbar.setupWithNavController(
Android 进阶资料
以下的资料是近年来,我和一些朋友面试收集整理了很多大厂的面试真题和资料,还有来自如阿里、小米、爱奇艺等一线大厂的大牛整理的架构进阶资料。希望可以帮助到大家。
Android 进阶核心笔记

百万年薪必刷面试题

最全 Android 进阶学习视频
评论