[안드로이드] onBackPressed와 onCancel의 차이점을 알 수 있을까요?

조회수 38회

dialog fragment를 구현한다음 띄운 창에서 뒤로가기 버튼을 구현하려는데

onBackPressed 버튼을 누르면 동작이 안하더군요..혹은 onBackPressedCallback() 이요

DialogFragment 의 경우에는 Activitywindow 상위에 발생 되기 때문에 최상단에서 back key 이벤트를 가로채게 된다고하는데.. 정확하게 무슨 말인지 모르겠습니다

다이얼로그가 back key이벤트를 가로채게 되는데 왜 onBackPressed의 구현(또는 onBackPressedCallBack이 동작안하는지

모르겠습니다..

그래서 뒤로가기를 구현하려면 onCancel을 구현하라는데 왜 그런건가요?

이 두개의 차이점이 무엇이지요

1 답변

  • 안녕하세요. 살펴보니 제가 예전에 드린 답변에서 혼동이 있으셨던 것 같습니다. 설명이 충분하지 않았던 것 같네요 :)

    Android 에서 최상단 View 는 Window 로 구성됩니다. 내부 클래스이므로 접근은 불가능 하지만 정확하게는 PhoneWindow 라는 클래스가 활용 되죠. 그리고 이것을 관리하는 WindowManager 클래스가 있습니다.

    Activity 는 각각의 Window 안에 생성 되며 Dialog 또한 Window 안에 생성 됩니다. 따라서, 어플리케이션의 UI 는 Window 가 겹겹이 쌓여있는 구조라고 볼 수 있습니다.

    "Dialog 가 back key 이벤트를 가로챈다" 라는 표현이 혼동의 여지가 있을 것 같은데요. 정확하게 표현하자면 KeyEvent 는 TouchEvent 처럼 Window 에 먼저 전달 되며 Activity (또는 dialog) -> View 이렇게 UI 계층을 따라 전달 됩니다. 실제로 중간에 이벤트를 가로채기 위한 onInterceptTouchEvent() 등의 API 가 존재하기도 하죠.


    본론으로 들어가면, Dialog 가 발생한 상태에서 back key 이벤트가 발생하면 Dialog 를 구성하는 Window 가 해당 이벤트를 받게 됩니다.

    또한 onBackPressedCallBackActivityonBackPressedDispatcher 를 통해 호출 됩니다. 그러나 이미 Activity 위에 새로운 Window 에서 Dialog 가 발생 하고 있고 이 Window 에서 먼저 KeyEvent 를 받기 때문에 onBackPressedCallback 을 사용 할 수 없는 것입니다.

    지난 답변에서 onCancel, onDismiss 를 언급 했던 것은 질문자님께서 어떤 시나리오를 구현하시고자 하는지 정확히 모르는 상태에서 말씀 드렸는데, 해당 callback 의 경우 Dialog 가 사라질 때 호출 되는 callback 이므로 위 질문에 대한 답변으로는 적절치 못한 것 같습니다.

    두가지 방법을 생각 해 볼 수 있는데요.

    첫번째는 Fragment 클래스는 onBackPressed() 를 제공하지 않으므로 Dialog 클래스의 onBackPresesed() 를 사용하는 방법입니다. onCreateDialog 에서 Dialog 생성 시 onBackPressed() 를 구현합니다.

     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return object : Dialog(requireContext()) {
            override fun onBackPressed() {
                //TODO: back key 이벤트 시 필요한 코드 추가
            }
        }
    }
    

    두번째 방법은 이미 생성 된 Dialog 객체에서 KeyListener 를 등록 한 뒤 Back key event 를 처리 하는 방식입니다.

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            dialog?.setOnKeyListener { dialog, keyCode, event ->
                if(keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
                    //TODO: back key 이벤트 시 필요한 코드 추가
                    return@setOnKeyListener true
                }
                return@setOnKeyListener false
            }
        }
    

    그러나 Dialog.java 코드를 살펴보면 onBackPressed() 의 호출은 이미 KeyListener 를 통해 구현 되어져 있기 때문에 내부 코드에 대한 차이점을 유의하시고 사용하시길 바랍니다.

답변을 하려면 로그인이 필요합니다.

Hashcode는 개발자들을 위한 무료 QnA 사이트입니다. 계정을 생성하셔야만 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)

ᕕ( ᐛ )ᕗ
로그인이 필요합니다

Hashcode는 개발자들을 위한 무료 QnA사이트 입니다. 계정을 생성하셔야만 글을 작성하실 수 있습니다.