[android] navigation fragment의 onBackPress 처리하기

원하는 조건

  • MainFragment는 back버튼을 두 번 눌러야 앱을 종료한다.
  • 다른 Fragment는 back버튼을 누르면 이전 화면으로 돌아간다.
  • 모든 Fragment는 BaseFragment를 상속받는다
open class BaseFragment : Fragment() {
  companion object {
    const val DONT_USE_BACK_BUTTON = "dont_use_back_button"
  }

  override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    // back 버튼을 사용하지 않는다고 설정하지 않은 화면에서는 back 버튼 사용하도록 설정
    if (savedInstanceState == null || !savedInstanceState.getBoolean(DONT_USE_BACK_BUTTON)) {
      activity?.onBackPressedDispatcher?.addCallback(backPressedDispatcher)
    }
  }

  /**
   * 이전 화면으로 이동. 마지막 화면이라면 앱 종료
   */
  protected fun navigateUp() {
    try {
      if (parentFragmentManager.backStackEntryCount == 0) {
        activity?.finish()
      } else {
        onNavigateUp()
        findNavController().navigateUp()
      }
    } catch (e: Exception) {
      Logg.w(e)
    }
  }

  /**
    * back 버튼 눌렀을 때
    */
    private val backPressedDispatcher = object : OnBackPressedCallback(true) {
      override fun handleOnBackPressed() {
        navigateUp()
      }
    }
}

이렇게 하면 따로 작업하지 않은 fragment에서는 back버튼을 누르면 이전 화면이나 앱을 종료 시키고, 만약 특정 화면에서는 back 버튼을 사용중지하거나, 다른 작업을 원할 때는 이렇게 하면 된다.

class MainFragment : BaseFragment() {
  override fun onActivityCreated(savedInstanceState: Bundle?) {
    activity?.onBackPressedDispatcher?.addCallback(onBackPressedCallback)

    val bundle = (savedInstanceState ?: Bundle()).apply {
      putBoolean(DONT_USE_BACK_BUTTON, true)
    }
    super.onActivityCreated(bundle)
  }

  // back 버튼 눌렀을 때
  private val onBackPressedCallback = object : OnBackPressedCallback(true) {
    override fun handleOnBackPressed() {
      // 원하는 작업하기
    }
  }
}