此 Codelab 是“使用 Kotlin 进行高级 Android 开发”课程的一部分。如果您按顺序学习这些 Codelab,您将会充分发掘课程的价值,但并不强制要求这样做。“使用 Kotlin 进行高级 Android 开发”Codelab 着陆页列出了所有课程 Codelab。
此 Codelab 基于使用 FirebaseUI 在 Android 上实现登录功能。如果您尚未完成上一个 Codelab,可以下载此 Codelab 的起始代码,但建议您先完成使用 FirebaseUI 在 Android 上实现登录功能 Codelab。
简介
如果您的应用支持登录,则一个常见的用例是将应用的部分内容仅供已登录的用户使用。例如,您可能希望仅允许已登录用户访问应用的设置界面。
对于此类情况,您可以使用条件导航,根据用户的身份验证状态将用户引导至相应的界面。
在此 Codelab 中,您将基于现有应用添加一个设置界面,该界面仅在用户登录后才可访问。您将使用 Android 的导航组件来完成此任务。
您应当已掌握的内容
- Android 的 Navigation 组件及其在 Android 应用中的使用方式
- 如何在 Android 应用中使用 FirebaseUI 库实现登录。如果您不熟悉此概念,则应完成 使用 FirebaseUI 在 Android 上实现登录功能这一 Codelab。
学习内容
- 如何根据用户是否已登录,将用户导航到应用的相应界面。
您将执行的操作
- 在用户成功登录后,正确处理将用户导航到正确屏幕的操作。
- 如果用户未登录,则禁止其访问设置界面,而是将其重定向到登录界面。
在上一个 Codelab 中,您处理了一个显示 Android 事实的应用。您的应用还允许用户登录和退出。在本 Codelab 中,您将向现有应用添加一个设置界面。只有在用户登录后,才能访问该设置界面。
如果用户未登录,则当他们尝试访问设置界面时,应用会将他们重定向到登录界面。登录流程成功完成后,用户将返回到他们最初尝试访问的设置界面。

此 Codelab 基于使用 FirebaseUI 在 Android 上实现登录功能。如果您尚未完成上一个 Codelab,可以下载此 Codelab 的起始代码,但建议您先完成使用 FirebaseUI 在 Android 上实现登录功能 Codelab。
若要下载示例应用,您可以执行以下操作之一:
…或从命令行使用下列命令克隆 GitHub 代码库,并切换到代码库的 start 分支:
$ git clone https://github.com/googlecodelabs/android-kotlin-login-navigation
在 Android Studio 中加载项目后:
- 在模拟器或实体设备上运行应用,确保您的环境已成功设置,可以开始开发。
如果成功,您应该会看到主屏幕,其中显示一条有趣的 Android 事实,并且左上角有一个登录按钮。
起始应用的当前功能:
- 如果用户未登录,点按登录按钮会启动登录流程,并允许用户使用电子邮件地址或 Google 账号登录。
- 如果用户已登录,该按钮会变为退出按钮,供用户退出登录。
在此任务中,您将在主屏幕上添加一个按钮,以便用户导航到设置界面。在设置界面中,用户可以选择要在主屏幕上显示的趣味事实类型。在设置界面中,他们可以选择查看有关 Android 的事实或有关加利福尼亚州的事实。

- 打开
fragment_main.xml。 - 在
fragment_main.xml,中添加一个嵌套在ConstraintLayout中的设置按钮,并将其放置在屏幕的右上角。
fragment_main.xml
<TextView
android:id="@+id/settings_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:background="@color/colorAccent"
android:padding="10dp"
android:text="@string/settings_btn"
android:textColor="#ffffff"
android:textSize="20sp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>- 打开
nav_graph.xml。 - 在
mainFragment内添加操作。相应操作的id为action_mainFragment_to_customizeFragment,目的地为customizeFragment。
nav_graph.xml
<fragment
android:id="@+id/mainFragment"
android:name="com.example.android.firebaseui_login_sample.MainFragment"
android:label="MainFragment">
<action
android:id="@+id/action_mainFragment_to_settingsFragment"
app:destination="@id/settingsFragment"/>
</fragment>- 打开
MainFragment.kt。 - 在
onViewCreated()中,为settings_btn设置onClickListener,以便用户点按该按钮时会导航到customizeFragment。
MainFragment.kt
binding.settingsBtn.setOnClickListener {
val action = MainFragmentDirections.actionMainFragmentToSettingsFragment()
findNavController().navigate(action)
}- 如果您看到未解决的错误,请从 Build 菜单重新编译应用,以生成并使用您创建的新导航操作。
- 重新启动应用。现在,右上角应该会显示一个可正常使用的设置按钮。
- 点击该按钮,系统应会带您前往设置界面。设置界面只有一个选项,可让用户选择要在主屏幕上显示的趣闻类型。
- 点击 Android 设备的返回按钮,返回主屏幕。

在此任务中,您将添加代码,以便在用户未登录的情况下尝试访问“设置”界面时,将用户导航到登录界面。
- 打开
SettingsFragment.kt。 - 在
onViewCreated()中,观察authenticationState,如果用户未通过身份验证,则将其重定向到LoginFragment。
SettingsFragment.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val navController = findNavController()
viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
when (authenticationState) {
LoginViewModel.AuthenticationState.AUTHENTICATED -> Log.i(TAG, "Authenticated")
// If the user is not logged in, they should not be able to set any preferences,
// so navigate them to the login fragment
LoginViewModel.AuthenticationState.UNAUTHENTICATED -> navController.navigate(
R.id.loginFragment
)
else -> Log.e(
TAG, "New $authenticationState state that doesn't require any UI change"
)
}
})
}由于应用会在用户尝试访问设置界面时将其带到登录界面,因此应用还需要处理登录界面上的返回按钮行为。如果应用未自定义返回按钮行为的处理方式,用户会陷入无限循环,即尝试返回到设置界面,但随后又被重定向到登录界面。
- 打开
LoginFragment.kt。 - 在
onViewCreated()中,通过将用户带回MainFragment来处理返回按钮操作。
LoginFragment.kt
// If the user presses the back button, bring them back to the home screen
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
navController.popBackStack(R.id.mainFragment, false)
}- 重新启动应用,并确认如果您未登录,尝试访问设置屏幕的操作现在会将您重定向到登录流程。
虽然您已成功将用户重定向到登录页面,但尚未处理用户成功登录后会发生的情况,因此登录尝试看起来好像不起作用。您将在下一步中修复此问题。
到目前为止,您已成功设置应用,以便在用户尝试访问设置界面但未登录时,将用户重定向到登录界面。
不过,在完成登录流程后,您会再次回到登录界面。这会带来不佳的用户体验,并可能让用户感到困惑。
为了提供理想的用户体验,应用应在用户成功登录后将其带回设置界面。
- 仍在
LoginFragment.kt的onViewCreated()中的任意位置,观察authenticationState,并在用户成功通过身份验证后将用户导航回SettingsFragment。
LoginFragment.kt
// Observe the authentication state so we can know if the user has logged in successfully.
// If the user has logged in successfully, bring them back to the settings screen.
// If the user did not log in successfully, display an error message.
viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
when (authenticationState) {
// Since our login flow is only one screen instead of multiple
// screens, we can utilize popBackStack(). If our login flow
// consisted of multiple screens, we would have to call
// popBackStack() multiple times.
LoginViewModel.AuthenticationState.AUTHENTICATED -> navController.popBackStack()
else -> Log.e(
TAG,
"Authentication state that doesn't require any UI change $authenticationState"
)
}
})- 再次运行应用,确认现在成功登录后,您会进入设置页面,而不是登录页面。
您可以在此 GitHub 代码库中查看包含所有解决方案代码的完整应用:https://github.com/googlecodelabs/android-kotlin-login-navigation。
在此 Codelab 中,您学习了有关如何在支持登录的应用中打造良好用户体验的最佳实践。通过观察应用的身份验证状态,您能够确定用户可以访问哪些界面,并在需要时将用户重定向到登录界面。
如需详细了解 Android 中导航方面的最佳实践,请查看以下资源:
Android 开发者文档:
Codelab:
如需本课程中其他 Codelab 的链接,请参阅“使用 Kotlin 进行高级 Android 开发”Codelab 着陆页。