뒤로가기 동작 제어 원리

액티비티에서 뒤로가기 이벤트가 발생시 OnBackPressed함수가 호출된다.

해당 함수를 오버라이드 해서 사용할 수 도 있지만 OnBackPressedCallback과 같은 콜백을 활용하여 액티비티와 뒤로가기 이벤트 사이의 결합도를 낮추고 유연한 코드 구조를 만들 수 있다.

동작 원리

  1. OnBackPressedCallback 1,2,3이 순서대로 OnBackPressedDispatcher에 등록된다.
  2. 뒤로가기 이벤트 발생
  3. 액티비티 내부의 onBackPressed함수가 호출된다.
  4. OnBackPressedDispatcher는 가장 마지막에 등록되었던 세번째 콜백 부터 순서대로 활성화 여부를 검토하여 가장 마지막에 추가된 활성화 된 콜백을 해당 이벤트에 연결한다.

구성요소

  • OnBackPressedDispatcher
    • back 버튼 이벤트를 하나 이상의 OnBackPressedCallback 객체로 전달되는 방법을 제어한다.
    • 쉽게 표현하자면 여러개의 뒤로가기 제어 로직 중 어떤 로직을 적용할지 결정해주는 역할을 한다.
    • 어떤 콜백을 연결 할지는 ‘책임연쇄 패턴(Chain of Responsibility)’을 따른다.
      • 대충 미리 설명하자면 가장 마지막에 추가된 활성화된 콜백을 실행한다.
    • 이외에도 제어와 관련된 다양한 기능을 사용할 수 있다.
    • 콜백 추가 시 addCallback() 함수를 사용하며, 이 때 lifecycleOwner를 함께 넘겨주면 라이프사이클에 따라 자동으로 콜백을 추가 및 제거하므로 메모리 누수 방지에 도움이 된다.

    (STARTED - 추가, DESTROY - 삭제)

  • OnBackPressedCallback

      public abstract class OnBackPressedCallback
        
      OnBackPressedCallback(boolean enabled)
    
    • 뒤로가기 이벤트(OnBackPressedDispathcer.onBackPressed)를 ComponentAcitity에 강하게 결합하지 않고 사용하기 위한 방법
    • 내부에 enable로 호출 제어
    • 해당 콜백이 enable 되어야만 해당 로직 실행

Chain of Responsibility Pattern : 책임 연쇄 패턴

  • 추가된 콜백은 추가된 순서의 역순으로 호출이 됨
  • 예를들어 one, two, three순으로 추가되었다면 three, two, one순으로 호출된다.
  • 체인의 각 콜백은 앞의 콜백이 enable=false일 경우에만 호출됨
  • 그니까 만약 three가 true라면 그냥 three가 호출되는거고 false라면 three다음인 two를 검토하고 활성화 되어있다면 호출한다.
case 나중에 추가된 콜백이 활성화 되어있는 경우 나중에 추가된 콜백이 비활성화 되어있는 경우
과정
결과 맨 마지막에 등록된 콜백이 활성화 되어 있으므로 해당 콜백이 호출된다. 맨 마지막 등록된 콜백이 비활성화 되어있으므로 해당 콜백의 다음 콜백을 검토하여 활성화된 가장 마지막 콜백을 실행한다.

Compose에서 뒤로가기 동작제어 : BackHandler

개요

@Composable
fun BackHandler(enabled: Boolean = true, onBack: () -> Unit): Unit

컴포즈에서는 BackHandler를 통해 위의 과정을 대체한다.

실제로 내부 코드를 보면 onBackPressedCallbackOnBackPressdDispatcher를 활용하여 위 과정과 같이 동작한다.

var backHandlingEnabled by remember { mutableStateOf(true) }
BackHandler(backHandlingEnabled) {
    // Handle back press
}

모든 컴포저블 내부에 BackHandler를 설정할 수 있지만 연쇄 책임 패턴에 따라 가장 내부의 BackHandler만 실행되며, 가장 내부의 BackHandlerfalse인 경우에는 그 전에 추가했던 BackHandler가 실행된다.

예제

깃헙 playground레포에서 배운 내용이 진짜인지 확인할 겸 BackHandler를 실험해 보았다.

엄청 자세한 예제는 아니고 책임 연쇄가 제대로 동작하는지 확인 하기 위한 코드이다.

아래 링크는 모두 같은 내용이며 편의를 위해 전부 올려두었다.

GithubRepo : github.com/gogumaC/playground

관련 이슈 : playground/issues/5

코드 : gogumac/playgroundforandroid/MainActivity.kt

PredictiveBackHandler

문서를 보다보니 PredictiveBackHandler라는 것도 있었다.

안드로이드 13부터 ‘예측가능한 뒤로가기’인가 하는게 슬슬 나오고 안드 14부터 적용된다고 하는데 그것과 관련이 있는 것 같다.

하여간 일반 BackHandler와 차이점은 BackHandler는 뒤로가기 버튼을 클릭 시 동작하는 로직이라면 PredictiveBackHandler는 뒤로가기 전반적인 동작을 추적하고 커스텀 할 수 있게 도와주는 느낌인 것 같다.

기능 실행시점 예측동작 사용사례
BackHandler 뒤로가기 버튼을 누른 즉시 X 뒤로가기 동작을 가로채 특정 동작으로 커스텀
PredictiveBackHandler 뒤로가기 제스처 감지시(버튼 누르기 전) O 뒤로가기 제스처에 대한 애니메이션이나 시각적 피드백 제공

사실 이것도 BackHandler랑 같이 실험해보려고 했는데 예측가능한 뒤로가기 적용하는게 실패해서 실행을 못시켜봐서 저게 완전히 맞는 건지는 잘 모르겠다.

다음에 사용할 일이 있으면 확인해봐야 할 것 같다.

참고

Jetpack Compose 뒤로가기 이벤트 처리하기

맞춤형 뒤로 탐색 기능 제공  |  Android Developers

뒤로 탐색 예측 동작 지원 추가  |  Android Developers

Compose 및 기타 라이브러리  |  Jetpack Compose  |  Android Developers

androidx.activity.compose  |  Android Developers

뒤로 탐색 예측 동작 지원 추가  |  Android Developers

예측 가능한 후면 디자인  |  Mobile  |  Android Developers

Activity  |  Jetpack  |  Android Developers

댓글남기기