包含登入功能的 Android 條件式導覽

這個程式碼研究室是「Android Kotlin 進階功能」課程的一部分。如果您按部就班完成每一堂程式碼研究室課程,就能充分體驗到本課程的價值,但這不是強制要求。如要查看所有課程程式碼研究室,請前往 Android Kotlin 進階功能程式碼研究室登陸頁面


本程式碼研究室是「在 Android 上使用 FirebaseUI 實作登入功能」的延伸內容。如果您尚未完成先前的程式碼研究室,可以下載本程式碼研究室的範例程式碼,但建議您先完成「使用 FirebaseUI 在 Android 上實作登入功能」程式碼研究室。

簡介

如果應用程式支援登入功能,常見的用途是僅供已登入的使用者存取部分內容。舉例來說,您可能想為已登入的使用者保留應用程式的「設定」畫面。

在這種情況下,您可以根據使用者的驗證狀態,使用條件式導覽將使用者帶往適當的畫面。

在本程式碼研究室中,您將以現有應用程式為基礎,新增設定畫面,只有登入的使用者才能存取。您將使用 Android 的導覽元件完成這項工作。

必備知識

課程內容

  • 如何根據使用者是否已登入,將他們導向應用程式的適當畫面。

學習內容

  • 在使用者成功登入後,正確處理將使用者導覽至正確畫面的程序。
  • 如果使用者未登入,請禁止他們存取「設定」畫面,並將他們重新導向至「登入」畫面。

在先前的程式碼研究室中,您開發的應用程式會顯示 Android 相關事實。您的應用程式也允許使用者登入及登出。在本程式碼實驗室中,您將在現有應用程式中新增設定畫面。使用者必須登入才能存取設定畫面。

如果使用者未登入,嘗試存取設定畫面時,應用程式會將他們重新導向至登入畫面。登入程序完成後,使用者會返回原本嘗試存取的設定畫面。

本程式碼研究室是「在 Android 上使用 FirebaseUI 實作登入功能」的延伸內容。如果您尚未完成先前的程式碼研究室,可以下載本程式碼研究室的範例程式碼,但建議您先完成「使用 FirebaseUI 在 Android 上實作登入功能」程式碼研究室。

下載範例應用程式,方法如下:

下載 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,並將其放置在畫面右上角。

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. 重新啟動應用程式。現在右上角應該會有可用的「設定」按鈕。
  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. 再次執行應用程式,確認現在成功登入後,您會前往「設定」頁面,而不是「登入」頁面。

如要查看包含所有解決方案程式碼的完整應用程式,請前往這個 GitHub 存放區:https://github.com/googlecodelabs/android-kotlin-login-navigation

在本程式碼研究室中,您已瞭解如何採用最佳做法,在支援登入的應用程式中打造優質的使用者體驗。觀察應用程式的驗證狀態後,您就能判斷使用者可存取哪些畫面,並在必要時將他們重新導向至登入畫面。

如要進一步瞭解 Android 導覽的最佳做法,請參閱下列資源:

Android 開發人員說明文件:

Codelabs:

如要查看本課程其他程式碼研究室的連結,請參閱 Android Kotlin 進階功能程式碼研究室登陸頁面。