前言

前段时间,我在做项目开发的时候对Fragment的管理遇到几个小问题,总觉得在现阶段封装好的Fragment管理器不太优雅。这成为我下决心学习Jetpack在很早之前推出的Navigation库,该库的诞生就是为了能够更加优雅的管理Fragment。在学习新知识时,我比较喜欢将我遇到的知识点与难点写在纸上。但有时由于时间比较紧,记在纸上的东西往往没有那么的详细与具体。所以我决定以后通过以写博客的方式对知识进行一个归纳总结,也希望能帮助到在看这篇博客的你。让我们一起来完善Android的知识体系吧!

使用条件

如果您要在 Android Studio 中使用 Navigation 组件,则必须使用 Android Studio 3.3 或更高版本。

添加依赖

要在您的项目中添加 Navigation 支持,请向应用的 build.gradle 文件添加以下依赖项:
dependencies {//...implementation "androidx.navigation:navigation-fragment-ktx:2.2.1"implementation "androidx.navigation:navigation-ui-ktx:2.2.1"
}

使用Navigation的具体流程

项目演示

新建三个Framgnet

在配置Navigation之前,我们创建三个Framgnet用于测试。代码如下所示:

//第一个Fragment
class Page1Fragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_page_1, container, false)}
}
//第二个Framgnet
class Page2Fragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_page_2, container, false)}
}
//第三个Fragment
class Page3Fragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_page_3, container, false)}
}

配置导航

  • 我们需要在res文件夹下新建一个navigaton文件夹。
  • navigaton文件夹下创建一个navigation资源文件
  • 我们将它起名为mobile_navigaion.xml

如下图所示:

<navigation>标签里可以嵌套另一个<navigation>标签,也可以新建一个navigation xml文件,通过<include>将其引进来。

在mobile_navigation.xml中添加上我们刚创建好的三个Fragment。

<fragment>标签下要有id,name,labellayout,这四个属性一定要齐全!代码如下所示:

<?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/mobile_navigation"><fragmentandroid:id="@+id/fragment_page_1_id"android:name="com.johnlion.navigation.Page1Fragment"android:label="fragment_page_1_label"tools:layout="@layout/fragment_page_1" /><fragmentandroid:id="@+id/fragment_page_2_id"android:name="com.johnlion.navigation.Page2Fragment"android:label="fragment_page_2_label"tools:layout="@layout/fragment_page_2" /><fragmentandroid:id="@+id/fragment_page_3_id"android:name="com.johnlion.navigation.Page3Fragment"android:label="fragment_page_1_label"tools:layout="@layout/fragment_page_3" /></navigation>

此时我们刚添加完Fragment的mobile_navigation.xml中,<navigation>标签在android studio编译器中会报红色警告,这是由于我们并未在Activity布局文件中添加好NavHostFragment

我们打开Activity布局文件,并在布局文件中添加一个NavHostFragment。代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><fragmentandroid:id="@+id/nav_host_fragment"android:name="androidx.navigation.fragment.NavHostFragment"android:layout_width="0dp"android:layout_height="0dp"app:defaultNavHost="true"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"app:navGraph="@navigation/mobile_navigation" /></androidx.constraintlayout.widget.ConstraintLayout>

请注意以下几点:

在添加NavHostFragment的时候编译器并未对NavHostFragment的文件路径、defaultNavHost与navGraph属性进行智能提示。请你不要慌,不要怀疑是否有这些属性或值,坚定准确的把它敲完或复制粘贴成功!
  • android:name 属性包含 NavHost 实现的类名称。
  • app:navGraph 属性将 NavHostFragment 与导航图相关联。导航图会在此 NavHostFragment 中指定用户可以导航到的所有目的地。
  • app:defaultNavHost="true" 属性确保您的 NavHostFragment 会拦截系统返回按钮。请注意,只能有一个默认 NavHost。如果同一布局(例如,双窗格布局)中有多个主机,请务必仅指定一个默认 NavHost。

NavHostFragment 简单来讲就是一个导航界面容器,用来展示导航中一系列的 Fragment。

NavHostFragment在Activity布局文件中添加成功后,mobile_navigation.xml中navigation标签的红色警告消失了,取而代之的是一个黄色的提醒,这是由于我们并未在navigation的标签中添加一个“起始目的地"!即我们打开应用的第一张页面。在<navigation>标签中添加上:

app:startDestination="@id/fragment_page_1_id"

此时在Navigation Edit中,作为起始目的地的Fragment顶部就会多了一个小房子。如下图所示:

这样我们创建好的Page1Fragment就会变成我们打开应用显示的第一个屏幕。

“起始目的地”配置好之后,我们需要为每一个fragment配置其的“目的地”。配置“目的地”的方式有两种,一种是在Navigation Edit中,拖拉可视化Fragment的箭头来指向它的“目的地”;第二种是直接在xml中,在每个Fragment中添加<action>标签,并配置好其“目的地”。代码如下所示:

<?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/mobile_navigation"app:startDestination="@id/fragment_page_1_id"><fragmentandroid:id="@+id/fragment_page_1_id"android:name="com.johnlion.navigation.Page1Fragment"android:label="fragment_page_1_label"tools:layout="@layout/fragment_page_1"><actionandroid:id="@+id/action_page_1_to_page_2"app:destination="@id/fragment_page_2_id" /></fragment><fragmentandroid:id="@+id/fragment_page_2_id"android:name="com.johnlion.navigation.Page2Fragment"android:label="fragment_page_2_label"tools:layout="@layout/fragment_page_2"><actionandroid:id="@+id/action_page_2_to_page_3"app:destination="@id/fragment_page_3_id" /><actionandroid:id="@+id/action_page_2_to_page_1"app:popUpTo="@id/fragment_page_1_id" /></fragment><fragmentandroid:id="@+id/fragment_page_3_id"android:name="com.johnlion.navigation.Page3Fragment"android:label="fragment_page_1_label"tools:layout="@layout/fragment_page_3"><actionandroid:id="@+id/action_page_3_to_page_2"app:popUpTo="@id/fragment_page_2_id" /></fragment></navigation>
应用导航图如下图所示:

实现跳转

接下来我们给每个Fragment配置好其对应的跳转事件。代码如下所示:

//第一个Fragment
class Page1Fragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_page_1, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)btn_page1.setOnClickListener {Navigation.findNavController(it).navigate(R.id.action_page_1_to_page_2)}}
}
//第二个Fragment
class Page2Fragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_page_2, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)btn_page2_1.setOnClickListener {Navigation.findNavController(it).navigateUp()}btn_page2_2.setOnClickListener {Navigation.findNavController(it).navigate(R.id.action_page_2_to_page_3)}}
}
//第三个Fragment
class Page3Fragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_page_3, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)btn_page3.setOnClickListener {Navigation.findNavController(it).navigate(R.id.action_page_3_to_page_2)}}
}

从中我们可以看出Fragment之间的跳转用到的API为:

  • Navigation.findNavController(view).navigate(actionID)
  • Navigation.findNavController(view).navigateUp()

使用Bundle传递参数

代码如下所示:

btn_bundle.setOnClickListener {val bundle = Bundle()bundle.putString("key", "value")Navigation.findNavController(it).navigate(R.id.action_page_1_to_page_2, bundle)}

通过创建一个Bundle()对象,把所要传递的key:value放进bundle里面,然后我们在的navigate(...)方法中把bundle传进去,这样我们就可以通过bundle来实现参数的传递了。

界面切换动画

我们可以在目的地之间添加上动画的过渡效果,使Fragment与Fragment之前切换不生硬。那么我们来尝试做个右进左出的动画吧。

我们先创建所需要的xml文件,在res目录下新建一个anim文件夹,用来存放实现动画的xml文件,然后新建两个动画资源文件,起名为slide_in_right.xmlslide_out_left.xml,代码如下所示:

//slide_in_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><translateandroid:duration="@android:integer/config_mediumAnimTime"android:fromXDelta="100%"android:interpolator="@android:anim/accelerate_interpolator"android:toXDelta="0" />
</set>//slide_out_left
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><translateandroid:duration="@android:integer/config_mediumAnimTime"android:fromXDelta="0"android:interpolator="@android:anim/accelerate_interpolator"android:toXDelta="-100%"/>
</set>

添加动画文件完成之后我们可以通过两种方法来配置Fragment与Fragment之间跳转的动画过渡,一种是在导航中的<action>标签下配置,另一种是通过代码中的navOptions方法进行配置,动画配置代码如下所示:

//我们对一张Fragment跳转到第二张Fragment进行动画配置
//第一种:xml静态配置<actionandroid:id="@+id/action_page_1_to_page_2"app:destination="@id/fragment_page_2_id"app:enterAnim="@anim/slide_in_right"app:exitAnim="@anim/slide_out_left" />//第二种:代码动态配置val option = navOptions {anim {enter = R.anim.slide_in_rightexit = R.anim.slide_out_left}}btn_page1.setOnClickListener {Navigation.findNavController(it).navigate(R.id.action_page_1_to_page_2, null, option)}

在代码中配置需要注意navigate(...)中第一个参数传入的是actionID,第二个参数传入的是bundle对象,由于我们并没有新建一个bundle,所以选择传入null,第三个参数则是navOptions

这样我们目的地与目的地之间的过渡动画就添加完成了~

到这里,通过运行预览,基本和示例一样效果了

使用 Safe Args 传递安全的数据

官方文档原话:
Navigation 组件具有一个名为 Safe Args 的 Gradle 插件,该插件可以生成简单的 object 和 builder 类,以便以类型安全的方式浏览和访问任何关联的参数。我们强烈建议您将 Safe Args 用于导航和数据传递,因为它可以确保类型安全。

先配置安全插件。

//顶级的build.gradlebuildscript {repositories {//...google()}dependencies {//...def nav_version = "2.1.0"classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"}}
//应用或模块级的build.gradle//...apply plugin: 'com.android.application'apply plugin: "androidx.navigation.safeargs.kotlin"android{//...kotlinOptions {jvmTarget = JavaVersion.VERSION_1_8}   }

添加安全插件完成后,它会自动生成末尾带有Directions的类,该类的名称是在源目的地的名称后面加上“Directions”,该类里面带有原目的地action的方法。

在官方文档中介绍,Navigation 库支持以下参数类型:


那我们来挑上几种类型尝试一遍吧。

首先我们需要在mobile_navigation.xml中添加上我们自定义的参数,假如我们打算从Page1中把参数传递给Page2,那么我们则需要在Page2(接收目的地)的<fragment>标签下添加上<argument>标签并添加上名字默认值类型三种属性。代码如下所示:

<fragmentandroid:id="@+id/fragment_page_2_id"android:name="com.johnlion.navigation.Page2Fragment"android:label="fragment_page_2_label"tools:layout="@layout/fragment_page_2"><!--...--><argumentandroid:name="myInteger"android:defaultValue="0"app:argType="integer" /><argumentandroid:name="myString"android:defaultValue="value"app:argType="string" /><argumentandroid:name="myBoolean"android:defaultValue="false"app:argType="boolean" /></fragment>

添加完成后一定要reBuild一下项目,这样安全插件会为我们生成末尾带有“Args”的类,里面有我们接收参数目的地即Page2获取参数的方法。

而且在Page1FragemntDirections类中,用来实现action的方法在reBuild后会更新成传递三个默认参数给Page2接收。代码如下所示:

class Page1FragmentDirections private constructor() {//...companion object {fun actionPage1ToPage2(myInteger: Int = 0,myString: String = "value",myBoolean: Boolean = false): NavDirections = ActionPage1ToPage2(myInteger, myString, myBoolean)}
}

接下来我们看下如何在代码中传递安全的数据。代码如下所示:

//Page1Fragment(传递安全数据)
class Page1Fragment : Fragment() {//...override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)btn_page1.setOnClickListener {val action = Page1FragmentDirections.actionPage1ToPage2(1, "hello", true)Navigation.findNavController(it).navigate(action)}
}
//Page2Fragment(接收安全数据)
class Page2Fragment : Fragment() {val args: Page2FragmentArgs by navArgs()override fun onViewCreated(view: View, savedInstanceState: Bundle?) {//...//获取的参数名为<argument>中配置好的nameLog.d("data", "integer:" + args.myInteger)Log.d("data", "string:" + args.myString)Log.d("data", "boolean:" + args.myBoolean)}
}

如果我们在actionPage1ToPage2(...)方法里什么都不加的话,就会把在xml设置好的android:defaultValue传递过去。

从Page1传递Page2的参数要求不能为null,但如果参数类型支持 null 值,那么可以在<argument>中,使用 android:defaultValue="@null"app:nullable="true"结合声明默认值 null。

总的来讲,safe args给我的感觉就是,通过其用来传递数据,就是为了避免接收数据时会报空指针异常

使用 NavigationUI 更新界面组件

导航架构组件包含 NavigationUI 类。此类包含使用顶部应用栏、抽屉式导航栏和底部导航栏管理导航的静态方法。

NavigationUI支持以下类型控件:

  • Toolbar
  • CollapsingToolbarLayout
  • ActionBar
  • DrawerLayout
  • BottomNavigationView

我们选择BottomNavigationView结合Navigation做一个示例:

  • 在res目录下下新建一个menu文件夹。
  • 在menu文件夹中创建一个menu资源文件起名为:menu.xml
  • 在此文件中添加上如下代码:
注意:item中的id必须要与在mobile_navigation.xml中你要显示的Fragment id一致
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:id="@+id/fragment_page_1_id"android:icon="@drawable/message"android:title="Page1" /><itemandroid:id="@+id/fragment_page_2_id"android:icon="@drawable/search"android:title="Page2" /><itemandroid:id="@+id/fragment_page_3_id"android:icon="@drawable/setting"android:title="Page3" />
</menu>

然后我们在Activity布局文件中添加BottomNavigationView控件,并把刚刚新创建好的menu文件关联其中。代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout ...><fragmentandroid:id="@+id/nav_host_fragment"... /><com.google.android.material.bottomnavigation.BottomNavigationViewandroid:id="@+id/bottom_navigation"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:menu="@menu/menu" />
</androidx.constraintlayout.widget.ConstraintLayout>

最后我们在activity的代码中需要先把NavController给取出来,再把它传进BottomNavigationView中的setupWithNavController(...)方法,而NavController是要在NavHostFragment里面取,所以第一步就是要把NavHostFragment找出来先,然后取出NavController,最后把它传递到setupWithNavController(...)方法里就完成Navigation与BottomNavigationView的绑定了。代码如下所示:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment? ?: returnval navController = host.navControllersetupBottomNavMenu(navController)}private fun setupBottomNavMenu(navController: NavController) {val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_navigation)bottomNav?.setupWithNavController(navController)}
}

演示效果如下:

但是!看演示的效果会发现,我们依次点击BottomNavigationView上面的item,Page2 -> Page3,然后停留在Page3中点击真机上面的back按键则会先跳回到Page1,再点一次才退出应用,再试几遍才发现只要你不是停留在Page1中点击back按键都会先返回到Page1中,再点击一次back按键才退出应用

我们要的效果是:只要点击BottomNavigation选择的Fragment,返回栈中只留它一个,再点击back按钮就可退出应用。

定位问题:

  • 进入bottomNav?.setupWithNavController(navController)方法里。
  • 发现里面只有一个NavigationUI.setupWithNavController(this, navController)方法,并进入该方法。
  • 里面有一个对BottomNavigationView实现的监听setOnNavigationItemSelectedListener里返回了一个onNavDestinationSelected(item, navController);,这个方法是用来关联Navigation与BottomNavigationView的MenuItem的。
  • 问题就是出自这个方法里的setPopUpTo(int destinationId, boolean inclusive),源码如下所示:
 public static boolean onNavDestinationSelected(@NonNull MenuItem item,@NonNull NavController navController) {NavOptions.Builder builder = new NavOptions.Builder()//...if ((item.getOrder() & Menu.CATEGORY_SECONDARY) == 0) {builder.setPopUpTo(findStartDestination(navController.getGraph()).getId(), false);}NavOptions options = builder.build();try {navController.navigate(item.getItemId(), null, options);return true;} catch (IllegalArgumentException e) {return false;}}

当我们每次点击BottomNavigationView的Item的时候,都会走setPopUpTo(...)方法,由于里面只指定“初始目的地”的id,所以每次都会弹出在其之上的目的地,且inclusive="false",这样“初始目的地”在栈中得到保留,并没有被移除!

这就是为什么:只要你不是停留在Page1中点击back按键都会先返回到Page1!


解决问题:

  • 问题出自一个叫onNavDestinationSelected(item, navController);的方法里。
  • 该方法里面只实现了导航跳转目的地,与设置跳转时的进出动画和目的地的启动模式
  • 此方法在BottomNavigationView的setOnNavigationItemSelectedListener监听里面。
  • 该监听只实现onNavDestinationSelected(item, navController)一个方法!

那我们可以试着重写BottomNavigationView的setOnNavigationItemSelectedListener监听,照着onNavDestinationSelected(...)方法里面的内容,修改成我们需要的效果不就行了!

activity代码如下所示:

class MainActivity : AppCompatActivity() {//...private fun setupBottomNavMenu(navController: NavController) {val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_navigation)bottomNav?.setupWithNavController(navController)//重写监听bottomNav.setOnNavigationItemSelectedListener { item: MenuItem ->val options = NavOptions.Builder()//从放回栈中移除指定目的地.setPopUpTo(navController.currentDestination!!.id, true).setLaunchSingleTop(true).build()try {//TODO provide proper API instead of using Exceptions as Control-Flow.navController.navigate(item.itemId, null, options)true} catch (e: IllegalArgumentException) {false}}}
}

演示效果如下:

完成!测试结果与我们想要的效果一致!

动态加载Navigation

先把Activity布局文件中的app:navGraph="@navigation/mobile_navigation"去掉先。代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout ...><fragmentandroid:id="@+id/nav_host_fragment"android:name="androidx.navigation.fragment.NavHostFragment"android:layout_width="0dp"android:layout_height="0dp"app:defaultNavHost="true"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

接着在Activity文件中,通过navController将Navigation的xml文件给inflater出来,并设置进navControllergraph中。代码如下所示:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment? ?: returnval navController = host.navControllerval navGraph: NavGraph =navController.navInflater.inflate(R.navigation.mobile_navigation)navController.graph = navGraph//...}//...
}

测试一遍,动态加载成功!

清空返回栈

假如我们打算从Page2跳到Page3时先把返回栈清空,然后跳转到Page3,这时返回栈应该就只有一个Page3的实例,当我们点击back’按键后,直接退出应用而不是放回Page2。

这是我在stackoverflow上找到了清空navigation返回栈的方法。

实现代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"...><!--...--><fragmentandroid:id="@+id/fragment_page_2_id"...><actionandroid:id="@+id/action_page_2_to_page_3"app:destination="@id/fragment_page_3_id"app:launchSingleTop="true"app:popUpTo="@+id/mobile_navigation"app:popUpToInclusive="true" /><!--...--></fragment>
</navigation>

在Page2跳转到Page3的<action>标签下添加上app:launchSingleTop="true"app:popUpTo="@+id/mobile_navigation"app:popUpToInclusive="true"就能实现先清空放回栈然后跳转

我们根据xml中添加的这些属性尝试在代码中实现。代码如下所示:

class Page2Fragment : Fragment() {//...override fun onViewCreated(view: View, savedInstanceState: Bundle?) {//...btn_page2_2.setOnClickListener {val navOption = NavOptions.Builder()//将xml中三个属性设置进去,就能实现先清栈后跳转.setLaunchSingleTop(true).setPopUpTo(R.id.mobile_navigation, true).build()Navigation.findNavController(it).navigate(R.id.action_page_2_to_page_3, null, navOption)}}
}
最后在Activity中实现一个全局清栈功能。

代码很简单,取出NavController,然后在调用navController.navigate(xxx)方法前调用navController.popBackStack(R.id.mobile_navigation, true)方法就能实现清栈。代码如下所示:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment? ?: returnval navController = host.navControllersetupBottomNavMenu(navController)}private fun clearStack(navController: NavController) {navController.popBackStack(R.id.mobile_navigation, true)}//...
}

当然“目的地”之间的跳转,应该统一放在activity里面管理,这里就不详细说明了。

只要拿到了navController,就能调用navController.navigate(xxx)进行“目的地”跳转。

总结

Android JetPack推出的Navigation架构组件,用来作为构建应用内界面的框架,其重点是让单Activity应用成为首选架构。此控件处理了FragmentTransaction 的复杂性,并提供了帮助程序,用于将导航关联到合适的 UI 小部件,例如抽屉式导航栏和底部导航。

项目链接

示例:android-navigation

参考文章

  • Android官方架构组件Navigation:大巧不工的Fragment管理框架
  • Android Navigation Architecture Component 使用详解
  • 官方文档
  • 官方项目地址
  • 官方项目教程

Android 官方架构组件 Navigation 使用详解相关推荐

  1. Android官方架构组件Paging:分页库的设计美学

    本文已授权 微信公众号 玉刚说 (@任玉刚)独家发布. 2019/12/24 补充 距本文发布时隔一年,笔者认为,本文不应该作为入门教程的第一篇博客,相反,读者真正想要理解 Paging 的使用,应该 ...

  2. Android架构组件Room功能详解,面试必问

    前言 在去年10月份的时候入职了一家外企,恰逢最近几周公司大规模招聘Android开发,有幸参与了十几场面试,遂有感而发.在其中也从面试官的方面有了一些想法,希望分享给大家. 本来当做面试官对于我来说 ...

  3. 字节跳动Android金三银四解析:Android架构组件Room功能详解,深度好文

    前言 很多公司在招人这件事情上都会面临一个问题: "我们的招聘要求又不高,能做项目就行,但为什么就是招不到人?" 很多公司还面临一个问题,招聘的时候这人各方面都不错,但上岗了就是不 ...

  4. Android 开发架构-MVC MVP MVVM详解

    何为架构 架构,即程序的逻辑组织结构,是指导开发过程中划分程序逻辑模块的关键,好的架构要使程序达到高内聚低耦合的设计目标.例如一个人,身体的骨骼即为身体的架构,有了基本骨架之后,才可以决定在头颅里开发 ...

  5. 安卓实例开发录音应用!Android架构组件Room功能详解,面试真题解析

    越来越多的人在提"移动端的下半场"."Android 开发的焦虑"之类的,也有人在喊"技术天天在变,学也学不完","昨天 Kotl ...

  6. android lifecycle,Android 架构组件之 LifeCycle详解

    1.Lifecycle介绍 为什么要使用lifecycle? activity 和fragment 是有声明周期的,有时候,我们的很多操作需要写在声明周期的方法中,比如,下载,文件操作等,这样很多情况 ...

  7. android官方架构room,Android 官方架构组件介绍之 Room(翻译)

    持久库Room Room在SQLite上提供了一个抽象层,以便在利用SQLite的全部功能的同时使流畅的数据库访问. 需要处理一些重要的结构化数据的App通常会从本地的持久数据中受益匪浅.最常见的就是 ...

  8. android官方架构组件,Android 架构组件官方文档01——LifeCycle

    使用生命周期感知组件处理生命周期 支持生命周期的组件执行操作以响应另一个组件(例如Activity和fragment)的生命周期状态更改.这些组件可帮助您生成组织性更好,并且通常更轻量的代码,这些代码 ...

  9. android 之四大组件的Activity详解

    Activity的生命周期: Activity的四种基本状态: (1) 运行态(Running) Activity处在最前端,用户可见可获得焦点 (2) 暂停态(Paused) Activity处在最 ...

最新文章

  1. 从2019 AI顶会最佳论文,看深度学习的理论基础
  2. CListCtrl 使用技巧
  3. matlab向量的模_基于MATLAB使用矩阵方法求解一维定态薛定谔方程
  4. [python爬虫] BeautifulSoup和Selenium对比爬取豆瓣Top250电影信息
  5. 文件夹操作之判断是否存在(Directory)
  6. 数据级并行--计算机体系结构
  7. Activiti工作流框架学习(一)环境的搭建和数据表的了解
  8. 和dump文件什么区别_将java进程转移到“解剖台”之前,法医都干了什么?
  9. 用计算机的知识服务社会,科研育人案例-董立红
  10. HDU 1695 GCD ★(容斥原理+欧拉函数)
  11. python 实例化对象_python如何实例化对象
  12. 只有搞Java开发的才知道!javaspring菜鸟教程
  13. ICCV 2021 | FACIAL :动态谈话人脸视频生成,姿态,眨眼皆可控!
  14. qt中clicked()和toggled()的区别
  15. 腾讯云即时通信IM实现聊天功能
  16. java 调用软键盘_关于Java:可靠地隐藏软键盘
  17. 项目管理(PMP)项目进度管理
  18. 【自学python爬虫】:入门书籍推荐(附资源)
  19. 服务器虚拟系统无法上网络设置,玩转Windows 2008虚拟机网络设置
  20. SWUSTOJ #971 统计利用先序遍历创建的二叉树的深度

热门文章

  1. 盐湖卤水中分离硼的工艺有哪些
  2. 怎么向java窗口中插入XSL表_Java向word中插入Excel文件对象
  3. python绝技 pdf 中文_虫术Python绝技 PDF 完整版
  4. C# 联合KepServer对PLC进行数据读写
  5. 翻开下一页——离开,再开始
  6. oracle有的表带$,Oracle Update
  7. 支付宝摘下客服界的“奥斯卡”奖 支付宝的D+服务厉害在哪?
  8. 如何才能能够提升个人自信
  9. 1g2g3g4g5g_5g之路
  10. “百度杯”CTF比赛 2017 二月场,题目名称:爆破-3