관리 메뉴

나만을 위한 블로그

[Android] targetSdkVersion 33 이후 onBackPressed() deprecated 이슈와 onBackPressedCallback() 사용법 본문

Android

[Android] targetSdkVersion 33 이후 onBackPressed() deprecated 이슈와 onBackPressedCallback() 사용법

참깨빵위에참깨빵_ 2022. 8. 1. 23:48
728x90
반응형

미디엄을 눈팅하던 도중 흥미로운 포스팅을 하나 봤다. 어제 날짜인 22.07.30일에 작성된 글이다.

 

https://oguzhanaslann.medium.com/onbackpressed-deprecated-so-what-to-use-92ddd55fc21d

 

OnBackPressed Deprecated So What to Use

If you have updated any application to targetSdk 33, you probably have seen that OnBackPressed() is deprecated in Activities.

oguzhanaslann.medium.com

앱을 targetSdk 33으로 업데이트한 경우 onBackPressed()가 액티비티에서 더 이상 사용되지 않는 것을 봤을 것이다

 

왜 그런 변화가 있는지 이야기해 보겠다. 안드로이드 10부터 시스템이 제스처 탐색 기능을 제공한다는 걸 알 수 있다
좀 더 자세히 설명하면 시스템은 왼쪽에서 오른쪽으로 스와이프해서 뒤로 이동하는 것과 같은 제스처를 지원한다(iOS와 동일). 그러나 이것은 앱에서 수평 스와이프와 결합됐을 때 예기치 않은 동작을 초래했다
사용자는 앱에서 수평으로 스와이프하는 동안 때때로 시스템을 다시 트리거했다고 보고했다. 문제는 제스처가 시스템 뒤로 또는 앱 뒤로 탐색을 한 것인지 안드로이드 시스템이 구별할 수 없다는 것이다. 즉 앱이 제스처를 처리하는지 여부를 알 수 없다

 

안드로이드 10(파이)은 2019년 9월에 공개된 버전으로 갤럭시 S10부터 적용됐다. 약 3년 전에 출시된 기종부터 적용되는 셈이다.

이 기종들부터 안드로이드는 아이폰처럼 스와이프 제스처 기능을 구현했는데 실제로 사용자들이 사용해보니 별로라서 그 해결책으로 OnBackPressedDispatcher라는 클래스를 사용할 것을 권장한다. 이것의 근거는 아래 링크에 있다.

 

https://developer.android.com/about/versions/12/behavior-changes-all?hl=ko#activity-lifecycle
 

동작 변경사항: 모든 앱  |  Android 12  |  Android Developers

모든 앱에 영향을 주는 Android 12의 변경사항을 알아봅니다.

developer.android.com

안드로이드 12에서는 작업의 루트에 있는 런처 액티비티에서 시스템 뒤로 누르기의 기본 처리를 변경한다. 이전 버전에선 시스템이 뒤로 누르기에서 이러한 액티비티를 완료했다. 안드로이드 12에선 이제 시스템이 액티비티를 완료하는 대신 액티비티와 그 작업을 백그라운드로 이동한다. 새 동작은 홈 버튼이나 동작을 사용해서 앱 외부로 이동할 때 현재 동작과 일치한다. 대부분의 앱에서 이 변경사항으로 인해 '뒤로'를 사용해서 앱 외부로 이동하는 사용자는 콜드 상태에서 앱을 완전히 다시 시작할 필요 없이 웜 상태에서 더 빠르게 앱을 재시작할 수 있다
앱이 현재 onBackPressed()를 재정의해서 뒤로 탐색을 처리하고 액티비티를 완료한다면 완료하는 대신 super.onBackPressed()를 호출하도록 구현을 업데이트한다...(중략)...또한 일반적으로 onBackPressed()를 재정의하는 대신 맞춤 뒤로 탐색을 제공하는 AndroidX Activity API를 쓰는 게 좋다. AndroidX Activity API는 시스템 뒤로 누르기를 가로채는 구성요소가 없으면 자동으로 적절한 시스템 동작을 따른다

참고) 시스템은 작업의 루트인 런처 액티비티에만 새 동작을 적용한다. 즉 ACTION_MAIN과 CATEGORY_LAUNCHER를 모두 써서 인텐트 필터를 선언하는 액티비티에 적용한다. 다른 액티비티의 경우 시스템은 액티비티를 완료해서 이전처럼 뒤로 누르기를 처리한다

 

위 링크로 들어가면 알겠지만 '맞춤 뒤로 탐색을 제공' 부분에 하이퍼링크가 걸려있다. 이것은 아래 링크를 확인하면 된다.

 

https://developer.android.com/guide/navigation/navigation-custom-back?hl=ko 

 

맞춤 뒤로 탐색 기능 제공  |  Android 개발자  |  Android Developers

맞춤 뒤로 탐색 기능 제공 뒤로 탐색 기능은 사용자가 이전에 방문한 화면 기록을 통해 뒤로 이동하는 기능입니다. 모든 Android 기기는 이 유형의 탐색을 위해 뒤로 버튼을 제공하므로 앱 UI에 뒤

developer.android.com

뒤로 탐색 기능은 사용자가 이전에 방문한 화면 기록을 통해 뒤로 이동하는 기능이다. 모든 안드로이드 기기는 이 유형의 탐색을 위해 뒤로 버튼을 제공하므로 앱 UI에 뒤로 버튼을 추가하면 안 된다. 사용자의 안드로이드 기기에 따라 이 버튼은 물리적 버튼 또는 소프트웨어 버튼이 될 수 있다
안드로이드는 사용자가 앱을 탐색할 때 대상의 백 스택을 유지한다. 일반적으로 안드로이드를 사용하면 뒤로 버튼을 누를 때 이전 대상으로 적절하게 이동할 수 있다. 하지만 최상의 사용자 환경을 제공하기 위해 앱에서 뒤로 이동하는 동작을 자체적으로 구현해야 하는 경우도 있다. 예를 들어 웹뷰를 사용할 때는 기본 뒤로 버튼 동작을 재정의해서 사용자에게 앱의 이전 화면 대신 웹 방문 기록을 통해 뒤로 이동하도록 하는 게 좋다

...(중략)...OnBackPressedDispatcher는 뒤로 버튼 이벤트가 하나 이상의 OnBackPressedCallback 객체로 전달되는 방법을 제어한다. OnBackPressedCallback의 생성자는 초기 사용 설정 상태를 나타내는 부울 값을 사용한다. 콜백이 사용 설정된 때(isEnabled()가 true를 반환) 디스패처가 콜백의 handleOnBackPressed()를 호출해 뒤로 버튼 이벤트를 처리한다. 사용 설정 상태는 setEnabled()를 호출해 바꿀 수 있다

콜백은 addCallback()을 통해 추가된다. LifecycleOwner를 취하는 addCallback()를 쓰는 게 좋다. 이렇게 하면 LifecycleOwner가 LifeCycle.State.STARTED일 때만 OnBackPressedCallback이 추가되게 할 수 있다. 액티비티는 연결된 LifecycleOwner가 제거될 때 등록된 콜백을 삭제할 수도 있으며 이는 메모리 누수를 방지하고 전체 기간이 액티비티보다 짧은 프래그먼트 또는 기타 생명주기 소유자에 사용하기 적합하다...(중략)

 

이후 내용은 프래그먼트의 onCreate()에서 onBackPressedDispatcher를 구현하는 예제기 때문에 생략한다.

 

onBackPressed()를 써서 뒤로 버튼 이벤트를 처리하고 있다면 이 메서드 대신 OnBackPressedCallback을 쓰는 게 좋다. 하지만 변경이 불가능하다면 다음 규칙이 적용된다

- addCallback()을 통해 등록된 모든 콜백은 super.onBackPressed()를 호출할 때 평가된다
- OnBackPressedCallback의 모든 등록된 인스턴스와 관계없이 onBackPressed는 항상 호출된다

 

그런데 나는 프래그먼트가 아니라 액티비티에서 사용하고 싶다. 프래그먼트는 제트팩 네비게이션을 사용하면서 어느 정도 백버튼에 대한 애로사항이 해결됐기 때문인 것도 있다.

그래서 예제 코드를 찾아보니 하나 찾게 되어 여기에 써둔다.

 

먼저 앱 수준 gradle에서 compileSdkVersion과 targetSdkVersion을 각각 33으로 설정해본다.

 

android {
    compileSdkVersion 33	// <- 33으로 설정
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.example.kotlinprac"
        minSdkVersion 26
        targetSdkVersion 33	// <- 33으로 설정

 

그리고 onCreate() 밖에 onBackPressed()를 만들어보자. 그러면 아래와 비슷하게 deprecated를 의미하는 삭선이 보일 것이다.

 

 

저 노란 경고줄을 클릭하고 Alt + Enter로 권장사항을 적용하면 아래와 같이 어노테이션이 하나 추가된다.

 

 

이제 이걸 써서 뒤로가기 클릭 시 로그를 출력하는 예제를 확인해 보자.

 

import android.os.Bundle
import android.util.Log
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import com.example.kotlinprac.R

class OnBackPressedTestActivity : AppCompatActivity() {

    private val TAG = this.javaClass.simpleName
    private val callback = object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            // 뒤로가기 클릭 시 실행시킬 코드 입력
            Log.e(TAG, "뒤로가기 클릭")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_on_back_pressed_test)

        this.onBackPressedDispatcher.addCallback(this, callback)
    }
}

 

OnBackPressedCallback()안에 true를 넣는 게 보인다. 이 true의 의미는 OnBackPressedCallback의 기본 활성화 상태로 false를 넣으면 handleOnBackPressed()가 호출되지 않고 onBackPressed() 처럼 작동해서 액티비티가 finish된다. 어떻게 되는지 직접 확인해보자.

handleOnBackPressed() 안에는 onBackPressed()에서 사용했던 코드들을 적절하게 넣으면 된다.

위의 예제 코드를 그대로 실행하면 아래와 같이 작동할 것이다.

 

 

백버튼을 누를 때마다 "뒤로가기 클릭" 로그가 찍히는 걸 볼 수 있다. 저기서 finish()를 호출하면 이전 화면이 있으면 그 화면으로 이동하거나 앱이 종료됐을 것이다.

 

OnBackPressedDispatcher와 이를 통해 호출할 수 있는 함수들을 확인하려면 아래 링크를 참고하면 된다.

 

https://developer.android.com/reference/androidx/activity/OnBackPressedDispatcher

 

OnBackPressedDispatcher  |  Android Developers

androidx.car.app.managers

developer.android.com

컴포지션을 통해 onBackPressed 콜백을 처리하기 위해 OnBackPressedCallback 인스턴스를 등록하는 데 사용할 수 있는 디스패처

 

이 방식은 원래 onBackPressed()가 없는 프래그먼트에서 백버튼을 눌렀을 때 동작을 제어하기 위해 사용했는데 onBackPressed()가 targetSdk 33 버전에서 deprecated되면서 대체재로 떠오르는 듯하다.

 

 

참고한 사이트)

 

https://devuryu.tistory.com/356

 

AndroidX 로 바뀌면서 Activity, Fragment 에 유용한 작업 기능

참고 한 Medium 글 How AndroidX changes the way we work with Activities and Fragments Over the last couple of months, many improvements to the Activity/Fragment APIs have been introduced via the Andr..

devuryu.tistory.com

 

https://wooyoung-tom.medium.com/android-fragment-%EC%97%90%EC%84%9C%EC%9D%98-backpress-%EB%8F%99%EC%9E%91-%EC%A0%9C%EC%96%B4-6e17173cb72e

 

[Android] Fragment 에서의 BackPress 동작 제어

Fragment 에서의 BackPress 동작 제어

wooyoung-tom.medium.com

 

반응형
Comments