Android API 33에서 개선된 predictive back gesture이다.
이름 그대로 예측 가능한 뒤로가기 동작이라는 의미이다.
이전 버전에서 back gesture를 지원할 때에는 단순히 화살표만 보여주었다.
그렇기 때문에 사용자들은 앱에서 화면을 오른쪽으로 Swipe를 할 때에도 실수로 앱이 닫히는 것을 예측하지 못하는 경우가 빈번했다.
이러한 이유로 Android 13에서는 화면이 작아지는 애니메이션을 추가하여 사용자의 동작이 앱을 종료하고 있음을 예측하도록 변경하였다.
Android API 33부터 onBackPressed() 콜백이 deprecated 되었다.
Back gesture는 특정 앱에서만 사용 가능한 것이 아니라, 안드로이드 시스템에서 지원하는 기능이다.
따라서, Back gesture를 사용하면 시스템이 Back Action을 Handling하기 때문에, 위 GIF처럼 뒤로 가기 애니메이션과 함께 앱이 작아지면서 종료된다.
즉, 안드로이드 시스템은 뒤로가기 Event에 대해 시스템의 Handling을 따를 것인지, 앱에서 정의한 Handling을 따를 것인지 알 수가 없다.
예를 들어, 어떤 Fragment에서 WebView를 통해 설문조사 화면을 보여주고 있다고 가정해보자.
설문을 진행하다가 이전 설문 내역을 수정하고자 Back gesture를 했다면 어떻게 될까?
별도의 처리를 해주지 않았다면, 시스템 Handling을 따르기 때문에 아예 Fragment가 backstack에서 pop되어 화면이 종료될 것이다.
이런 Bad UX를 최소한으로 하기 위해, 시스템의 Back Action을 intercept하여 개발자의 의도대로 커스텀할 필요가 있다.
따라서 개발자가 Back Event을 intercept하여 여러 상황에 맞추어 직접 Handling 할 수 있도록 권장하고 있다.
안드로이드 공식 문서에 따르면, 이에 대응하기 위해 OnBackInvokedCallback 또는 OnBackPressedCallback을 사용하기를 권장한다.
+ ) 뒤로가기 버튼을 누르던, 뒤로가기 제스쳐를 하던 동일하다. 다만 API 33 으로 업데이트되면서 사용자에게 뒤로가기에 대한 더 나은 UX를 제공해주고자, predictive back gesture, 시스템 Back Event intercept 등을 지원하여 개발과 이용에 편리함을 제공하는 것 같다.
따라서 소개할 내용은 back gesture에만 한정된 내용이 아님을 밝힌다.
OnBackInvokedCallback
- android library에서 지원한다.
- API 33부터 사용 가능하다. (이전 버전 기기에서 실행하면 예외 발생)
- AndroidManifest의 Application 속성으로 android:enableOnBackInvokedCallback = {true | false} 설정함에 따라 호출 여부가 결정된다.
- Android 13에서 기본 값은 false이며, predictive back gesture 애니메이션 사용을 중지한다.
- Android 14부터 기본 값이 true이므로 따로 설정해주지 않으면 시스템의 Back gesture를 가로챈다.
- android:enableOnBackInvokedCallback 속성은 당연히 API 33부터 적용되며, 그 이전 버전에서는 무시된다.
OnBackPressedCallback
- androidX library에서 지원한다. (API 33 이전 버전도 사용 가능하다.)
- android:enableOnBackInvokedCallback 설정 여부와 관계없이 호출된다.
- android:enableOnBackInvokedCallback가 false이면 onBackPressed() 함께 호출된다.
- Fragment에서 뒤로가기 처리를 할 때에도 사용된다.
만약 androidX를 사용하지 않는 프로젝트라면, onBackInvokedCallback을 사용할 수 있도록 API 33부터 제공한다.
중요한 것은 위 두 콜백과 관계없이, android:enableOnBackInvokedCallback = {true | false}를 true로 설정하면 Back gesture를 시스템 Handling을 하지 않기 때문에 override한 onBackPressed()가 호출되지 않는다.
정리하자면, 시스템 Back Event를 가로채는 것은 android:enableOnBackInvokedCallback 값으로 결정된다.
구현
// In your build.gradle file:
dependencies {
// Add this in addition to your other dependencies
implementation "androidx.activity:activity:1.6.0-alpha05"
만약 AndroidX를 사용 중이고 OnBackPressedCallback을 사용할 것이라면 위 의존성을 추가해준다.
그렇지 않다면 의존성을 추가하지 않고 OnBackInvokedCallback을 사용한다.
<application
...
android:enableOnBackInvokedCallback="true"
API 33을 지원한다면 위 속성을 추가해 주어야 한다.
해당 속성을 추가해주어야 시스템의 Back Event를 가로채어 앱에서 다룰 수 있다.
OnBackInvokedCallback을 등록했더라도 위 속성값이 false이면, 기존 onBackPressed() 콜백이 호출된다. (disable이기 때문..)
Android 13에서는 기본값이 false이지만, Android 14부터 기본값이 true이다.
OnBackInvokedDispatcher
if (BuildCompat.isAtLeastT()) {
onBackInvokedDispatcher.registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT
) {
Log.d("buna", "OnBackInvokedCallback")
}
}
API 33부터 지원하는 InvokedDispatcher는 위와 같은 코드로 등록할 수 있다.
최소 티라미수 버전 이상인 경우에만 콜백을 등록해야 한다.
그렇지 않으면 예외가 발생하여 앱이 종료된다.
android:enableOnBackInvokedCallback를 true로 설정하고 OnBackInvokedDispatcher를 사용하면, onBackPressed()는 호출되지 않는다.
반대로 속성값이 false라면 기존의 onBackPressed()가 호출될 것이다.
OnBackPressedCallback
onBackPressedDispatcher.addCallback(this, object: OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
Log.d("buna", "OnBackPressedCallback")
}
})
AndroidX를 사용하고 있다면 API 33 이전이더라도 콜백을 등록할 수 있다.
PressedDispatcher는 android:enableOnBackInvokedCallback 속성과 무관하게 호출된다.
따라서 속성값이 false라도 OnBackPressedCallback(enabled)에 true를 전달하면 항상 호출된다.
OnBackInvokedDispatcher와 다르게 기존 onBackPressed() 콜백이 함께 호출되므로 주의해야 한다.
또한, addCallback()의 첫 번째 인자로 lifeCycleOwner를 넘겨주면 Dispatcher가 lifecycle을 알 수 있다.
따라서 lifecycle이 종료될 때, 자체적으로 콜백을 해제해준다.
메모리 누수를 방지하기 위해서 반드시 전달해주어야 한다.
val backPressCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
Log.d("buna", "OnBackPressedCallback")
}
}
...
backPressCallback.isEnabled = false // any if expression
경우에 따라 콜백을 비활성화해야 할 수도 있다.
그럴 때에는 callback의 isEnabled을 false로 지정하면 된다.
'Android' 카테고리의 다른 글
[Android] OkHttp & Retrofit (4) | 2023.06.06 |
---|---|
[Android] BroadcastReceiver 보안 이슈 (1) | 2023.05.17 |
[Android] PendingIntent 공식문서 파헤치기 (0) | 2023.05.02 |
[Android] RecyclerView Animation (LayoutAnimation, ItemAnimator) (0) | 2023.04.28 |
[Android] Listview vs RecyclerView (1) | 2023.04.20 |