목차
- Configuration 소개
- Activity Recreate
- 상태 보존
- 생성 제한
- 결론
Configuration 소개
Configuration 클래스는 응용 프로그램 리소스에 영향을 줄 수 있는 모든 장치 구성 정보를 설명한다. 여기에는 사용자 지정 옵션(화면 스케일, 로케일, 입력 모드, 화면 방향 전환, 화면 크기와 같은 장치 구성 정보가 포함된다. val config = resources.configuration와 같이 접근할 수 있다.
일부 기기 구성은 앱이 실행되는 동안 변경될 수 있다. 여기에는 다음이 포함되지만 이에 국한되지 않는다.
- 앱 디스플레이 크기
- 화면 방향
- 글꼴 크기 및 두께
- 언어
- 어두운 모드와 밝은 모드 비교
- 키보드 사용 가능 여부
구성 변경은 대부분 사용자 상호작용으로 인해 발생한다. 예를 들어, 기기를 회전하거나 접으면 앱에서 사용할 수 있는 화면 크기가 달라진다. 마찬가지로 글꼴 크기, 언어, 기본 테마와 같은 기기 설정을 변경하면 Configuration 객체에서 각각의 값이 변경된다. 이런 변경 사항을 적용하려면 애플리케이션 UI 사이즈를 조정해야 한다.
Activity Recreate
시스템은 Configuration Change가 발생하면 Activity를 다시 만든다. 시스템에서 onDestroy()를 호출하고 기존 Activity 인스턴스를 소멸시킨 후 onCreate()를 호출해서 새로운 인스턴스를 만든다. 새로운 Activity 인스턴스는 초기화되며 UI도 다시 만든다.
상태 보존
그러나 사용자 입장에서 이러한 변경이 생길때 마다 초기화된 앱을 사용하는 것이 항상 좋은 경험은 아니다. Configuration Change 및 Activity Recreate가 발생했을 때 일관된 환경을 보장하는 것이 필요하다.
- 기기 회전
- 멀티 윈도우 모드 시작
- 멀티 윈도우 모드나 자유 형식 창에서 애플리케이션 크기 조절
- 여러 디스플레이가 제공되는 폴더블 기기 접기
- 시스템 테마 변경(예: 어두운 모드 또는 밝은 모드)
- 글꼴 크기 변경
- 시스템 또는 앱 언어 변경
- 하드웨어 키보드 연결 또는 연결 해제
- 도크(Dock) 연결 또는 연결 해제
위에 나열되어 있는 Configuration Change를 발생시킨 후 Activity가 재생성될 때 관련 상태를 보존하는 세 가지 방식을 활용할 수 있다.
- 영구 로컬 저장소(Database, DataStore)는 애플리케이션이 사용자 기기에 설치되어 있는 동안(별도로 데이터를 삭제하지 않는 한) 유지된다. 로컬 저장소에 데이터를 저장한 후 재생성된 Activity에서 UI 관련 데이터를 로드하여 UI 상태를 복구한다.
- ViewModel은 Configuration Change가 발생하더라도 메모리에 남아 있으며 시스템이 재 생성한 인스턴스와 ViewModel을 자동으로 연결한다. ViewModel은 UI 관련 상태 처리를 하기 적합하다.
- View System의 onSaveInstanceState() 콜백, Jetpack Compose의 rememberSaveable, ViewModel의 SavedStateHandle은 시스템이 Activity, Fragment와 같은 UI Controller가 제거되고 나중에 다시 생성할 때 UI Controller의 상태를 다시 로드하는 데 필요한 데이터를 저장할 수 있다.
생성 제한
특정 Configuration Change가 발생했을 때 자동 Activity 재생성을 방지할 수 있다. 특수한 상황에서 Activity를 다시 만들지 않는 것이 더 적절한 경우가 있을 수 있다. 이러한 경우 재생성을 하지 못하도록 설정할 수 있다.
<activity
android:name=".MyActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:label="@string/app_name">
AndroidManifest.xml의 <activity> 항목에 android:configChanges 속성을 추가한다. 가능한 값은 문서에 나와있다. 위의 예제 코드는 화면 방향과 키보드 사용 가능 여부가 변경될 때 MyActivity의 재생성을 사용 중지로 설정한다.
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Checks whether any keyboard is available
if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show()
} else if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_NO) {
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show()
}}
뷰 시스템에서 Activity 재생성을 사용 중지한 후 Configuration Change가 발생하면 Activity는 onConfigurationChanged() 콜백을 수신한다. 모든 연결된 뷰 또한 View.onConfigurationChanged() 콜백을 수신한다.
주의 : Configuration Change를 직접 제어하는 것은 리소스를 사용하는 데 훨씬 까다로워질 수 있다. 시스템이 자동으로 이를 처리해주지 않기 때문이다. 이 기법은 최후의 수단이며, 대부분 애플리케이션에서 권장하지 않는 방법이다.
결론
안드로이드에서 블루투스 연결을 개발하면서 Configuration 관련해서 다시 한 번 복습하는 시간을 가지게 되었다. 블루투스 연결을 통해 다양한 기기와 연결하다보면 스캐너가 키보드로 인식된다거나 하는 이슈들이 있을 수 있는데, 이러한 상황들을 애플리케이션 범위 내에서 잘 이해하려면 Configuration에 대한 개념을 제대로 숙지하고 있어야 한다는 것을 다시 한 번 깨닫고 기본기를 더 탄탄하게 다지는 계기가 되었던 것 같다.
Configuration | Android Developers
구성 변경 처리 | Android 개발자 | Android Developers