通过登录进行 Android 条件导航

此 Codelab 是“使用 Kotlin 进行高级 Android 开发”课程的一部分。如果您按顺序学习这些 Codelab,您将会充分发掘课程的价值,但并不强制要求这样做。“使用 Kotlin 进行高级 Android 开发”Codelab 着陆页列出了所有课程 Codelab。


此 Codelab 以使用 FirebaseUI 在 Android 上实现登录为基础。如果您未完成上一个 Codelab,可以下载此 Codelab 的起始代码,但建议您先完成使用 FirebaseUI 在 Android 平台上实现登录 Codelab。

简介

如果您的应用支持登录,常见的做法是仅为登录用户保留部分应用内容。例如,您可能希望为已登录的用户保留应用的设置屏幕。

在这种情况下,您可以使用条件导航,根据用户的身份验证状态将用户引导至适当的屏幕。

在此 Codelab 中,您将基于一个现有应用进行构建,以添加一个设置屏幕,用户只有在登录后才能访问屏幕。您将使用 Android 的导航组件来完成此任务。

您应当已掌握的内容

学习内容

  • 如何根据用户是否已登录来将用户导航到应用的相应屏幕。

您将执行的操作

  • 在用户成功登录后,正确处理将其导航到正确的屏幕。
  • 如果用户尚未登录,则禁止他们访问设置屏幕,而是将用户重定向到登录屏幕。

在上一个 Codelab 中,您开发了一款显示 Android 事实的应用。您的应用还允许用户登录和退出。在此 Codelab 中,您将向现有应用添加设置屏幕。只有已登录的用户才能访问设置屏幕。

如果用户没有登录,则当用户尝试访问设置屏幕时,应用会将他们重定向到登录屏幕。成功完成登录流程后,用户会返回到他们最初尝试访问的设置屏幕。

本 Codelab 是在使用 FirebaseUI 在 Android 设备上实现登录的基础上构建的。如果您未完成上一个 Codelab,可以下载此 Codelab 的起始代码,但建议您先完成使用 FirebaseUI 在 Android 平台上实现登录 Codelab。

下载示例应用,您可以执行以下任一操作:

下载 Zip 文件


... 或者从命令行使用以下命令克隆 GitHub 代码库并切换到代码库的 start 分支:

$  git clone https://github.com/googlecodelabs/android-kotlin-login-navigation

在 Android Studio 中加载项目后,执行以下操作:

  1. 在模拟器或实体设备上运行应用,确保您的环境已成功设置以开始开发。

如果成功,您应该会看到主屏幕显示有趣的 Android 信息,并显示一个登录按钮。


起始应用的当前功能:

  • 如果用户尚未登录,则点按登录按钮会启动登录流程,并允许用户使用电子邮件地址或 Google 帐号登录。
  • 如果用户已登录,该按钮会更改为退出按钮,让用户可以退出。

在此任务中,您将在主屏幕上添加一个按钮,供用户导航到设置屏幕。用户可以通过设置屏幕,选择希望在主屏幕上显示的有趣的小知识。在设置屏幕中,用户可以选择查看有关 Android 的信息,也可以查看有关加利福尼亚州的信息。

  1. 打开 fragment_main.xml
  2. fragment_main.xml, 中,添加嵌套在 ConstraintLayout 中的 Settings 按钮,并将其放置在屏幕的右上角。

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"/>
  1. 打开 nav_graph.xml
  2. mainFragment 中添加一个操作。该操作的 idaction_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>
  1. 打开 MainFragment.kt
  2. onViewCreated() 中,为 settings_btn 设置 onClickListener,以便点按相应按钮将用户导航到 customizeFragment

MainFragment.kt

binding.settingsBtn.setOnClickListener {
   val action = MainFragmentDirections.actionMainFragmentToSettingsFragment()
   findNavController().navigate(action)
}
  1. 如果您看到未解决的错误,请从 Build 菜单重新编译应用,以生成并使用您创建的新导航操作。
  2. 重新启动应用。现在,右上角的 Settings 按钮应该可以正常运行。
  3. 点击该按钮应该会转到设置屏幕。设置屏幕只有一个选项,可让用户选择希望在主屏幕上显示的有趣的事实类型。
  4. 点击 Android 设备的返回按钮可返回主屏幕。

在此任务中,您将添加代码,以便在用户未登录时尝试访问设置屏幕时,将用户转到登录屏幕。

  1. 打开 SettingsFragment.kt
  2. 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"
           )
       }
   })
}

由于当用户尝试访问设置屏幕时,应用会将用户转到登录屏幕,因此应用还需要处理登录屏幕上的返回按钮行为。如果应用未自定义处理返回按钮行为,用户将在尝试返回到设置屏幕时陷入无限循环,然后又被重定向到登录屏幕。

  1. 打开 LoginFragment.kt
  2. 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)
}
  1. 重新启动您的应用,并确认如果您未登录,现在尝试访问设置屏幕会将您重定向到登录流程。

尽管您已成功重定向用户以登录,但您并未处理用户成功登录之后所发生的情况,因此尝试登录的操作似乎失败了。您将在接下来的步骤中解决此问题。

到目前为止,您已成功将应用设置为在用户尝试在不登录的情况下访问设置屏幕时,将用户重定向到登录屏幕。

但是,在完成登录流程后,您将返回到登录屏幕。这样的用户体验并不是很好,而且会令人感到困惑。

为了提供理想的用户体验,应用应在用户成功登录后将用户带回设置屏幕。

  1. 还是在 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"
       )
   }
})
  1. 再次运行应用,并在成功登录时确认现在会进入 Settings(设置)页面,而非 Login(登录)页面。

您可以在此 GitHub 代码库 https://github.com/googlecodelabs/android-kotlin-login-navigation 中查看包含所有解决方案代码的完整应用。

在此 Codelab 中,您学习了有关如何在支持登录的应用中打造良好用户体验的最佳做法。通过观察应用的身份验证状态,您能够确定用户可以访问哪些屏幕,并根据需要将其重定向到登录屏幕。

如需详细了解 Android 中的导航最佳做法,请参阅以下资源:

Android 开发者文档:

Codelab:

如需查看本课程中其他 Codelab 的链接,请参阅“使用 Kotlin 进行高级 Android 开发”的 Codelab 着陆页。