
이전에 작성한 포스팅(Activity 재생성이 발생하는 경우와 그에 대한 권고 대비 사항)에선 Activity재생성이 발생하는 경우와 그에 대한 안드로이드에서 권장하는 대비법에 대해 알아봤있다. 개괄적으로 말해보자면, Activity재생성은 '구성 변경'과 '프로세스의 강제 종료'등의 사유로 발생하는데, 이는 onDestroy()까지 호출했다가, onCreate()를 호출하는, 즉 말 그대로 Activity를 다시 생성하는 작업을 의미한다. 또한 Activity생명주기 중간에 onSaveInstanceState()와 onRestoreInstanceState()을 호출했었다.
[Activity 재생성 생명주기]
onPause()onStop()onSaveInstanceState()onDestroy()onCreate()onStart()onRestoreInstanceState()onResume()
하지만, '구성 변경'으로 인해 발생하는 Activity재생성은 Manifest.xml에 android:configChanges설정을 통해 Activity재생성을 방지할 수 있다.
이번 포스팅에선 위 내용을 토대로, Android공식 홈페이지가 권고하는 '구성 변경'에 대한 내용을 정리한 글이다.
갤럭시 앱 기준, '설정'앱에 들어가면 앱의 여러 설정을 변경할 수 있다. 언어, 글자 크기, 글자 두께, 외부 키패드 연동, 테마 변경 등이 가능하다. Android Framework에선 이러한 설정 정보를 Configuration이란 객체에 담고있는데, 이를 '구성'이라고 한다. 이러한 구성 리스트는 Android공식 홈페이지에 android:configChanges설정 목록에서 볼 수 있다.
| 값 | 설명 |
|---|---|
| colorMode | 화면의 색상 모드 기능(색상 범위 또는 동적 범위)이 변경되었을 때. |
| density | 화면 밀도 변경(예: 사용자가 디스플레이 크기를 조정하거나 다른 디스플레이가 활성화). |
| fontScale | 글꼴 배율 변경(예: 사용자가 새 전체 글꼴 크기를 선택). |
| fontWeightAdjustment | 글꼴 두께 증가/감소 값이 변경되었을 때. |
| grammaticalGender | 언어의 문법적 성이 변경되었을 때(GrammaticalInflectionManager 참고). |
| keyboard | 키보드 유형 변경(예: 사용자가 외부 키보드를 연결). |
| keyboardHidden | 키보드 접근성 변경(예: 사용자가 하드웨어 키보드를 표시/숨김). |
| layoutDirection | 레이아웃 방향 변경(좌→우 LTR ↔ 우→좌 RTL). (API 17+) |
| locale | 언어 변경(예: 사용자가 텍스트를 표시할 새 언어를 선택). |
| mcc | MCC(모바일 국가 코드) 변경. |
| mnc | MNC(모바일 네트워크 코드) 변경. |
| navigation | 탐색(물리/트랙볼 등) 구성 변경. 일반적으로는 발생하지 않음. |
| orientation | 화면 방향 변경(예: 사용자가 기기를 회전). |
| screenLayout | 화면 레이아웃 변경(예: 다른 디스플레이가 활성화되는 경우). |
| screenSize | 현재 사용 가능한 화면 크기 변경(전체 사용 가능 영역 기준으로 크기 변경). |
| smallestScreenSize | 실제 화면의 최소 너비가 변경(외부 디스플레이로 전환/분할 등). (API 13+) |
| touchscreen | 터치 스크린 모드 변경(예: 입력 주변기기를 연결/해제). |
| uiMode | 사용자 인터페이스 모드 변경(예: 야간/자동/자동차/TV 등; UiModeManager 참고). |
말 그대로, 사용자가 '설정'앱에 들어가, 위의 말한 설정을 변경하므로써, Configuration객체 내부 상태가 변경되는걸 의미한다.
사용자는 구성변경 이후, 이러한 설정이 올바르게 적용되어, UI에 즉시 반영되길 기대한다. 예를 들어, 어르신이 글자가 너무 작아 크기를 키웠다거나, 외국인이 언어를 한국어에서 영어로 변경하는 경우가 있다. 이런한 설정 변경 작업이 일어났을 때, 앱은 그러한 설정을 반영해줘야 한다.
Activity재생성 발생에 따라, 정보를 저장해야할 경우가 있다. 그럴 땐, 이전 포스팅(Activity 재생성이 발생하는 경우와 그에 대한 권고 대비 사항)에 써놨듯이 onSaveInstanceState()/onRestoreInstanceState() or rememberSaveable(), SaveStateHandle()을 활용한 상태 유지가 가능하다.
이에 대한 대비법으로 Manifest.xml의 android:configChanges를 설정하고, Activity 재생성을 방지한다면, Activity의 정보는 유실되지 않는다. 따라서 이 방법이 더 보이기도 한다. 하지만 이게 꼭 좋은걸까?

결론부터 말하면, android:configChanges를 설정한다 해도, '구성 변경'에 따른 Activity의 재생성을 100% 방지할 수 없다. 왜냐하면 Android 12L때 도입 된 '동적 색상 변경'의 경우, Manifest.xml에 android:configChanged로도 이를 제어할 수 없기 때문이다.
또한 구성 변경의 의미를 되짚어 보면, 이는 구성 변경에 따른 UI 상태의 즉시 동기화가 이뤄져야만 한다. 예를 들어, 언어를 영어로 바꿨을 땐, 앱의 언어를 영어로 바꿔줘야하고, 테마를 다크모드로 바꿨을 땐, 다크모드로 바꿔줘야 하는것 처럼 말이다. 따라서 구성 변경에 따른 Activity의 재생성을 막아버리는 행위는, 개발자가 onConfigurationChanged() 또는 LocalConfiguration.current를 통해 UI 동기화 작업을 수동으로 진행해야 하는 만큼, 리소스 할당 작업의 수고로움이 더 들 수 있다. 따라서 구성 변경이 발생했을 땐, 오히려 Activity재생성을 유도해주고, 그에 따른 필요 리소스들을 UI에 자동 적용해주는 편이 더 편할수도 있다.
아래는 Android공식 홈페이지에서 구성 변경이 발생했을 때, Activity재생성을 권고하는 말을 문장을 바꿔가며 여러번 강조하고 있다.
더 나아가, Android 12L땐 동적 테마 변경에 따른 Activity구성 변경을 막을 수 없다.
[Android 12L 동적 색상 변경 시, 무조건적인
Activity재생성]
뿐만 아니라, 구성 변경에 따른 onConfigurationChanged()의 콜백 호출이 Android12, 12L 13 버전에선 적절히 호출되지 않는 버그 또한 보고된 바 있다. 따라서 해당 기기 버전의 하위 호환을 신경써야하는 앱이라면, 차라리 Activity재생성을 유도해주는 게 더 좋은 선택지일 수도 있다.
[Google Issue Tracker]
아래 이슈는 실제 올라온 이슈로,onConfigurationChanged()의 호출 이슈로,LocalConfiguration.current로의 상태값이 제대로 전달되지 않는 이슈이다.
참고 : Google Issue Tracker

Activity재생성이 발생한다.android:configChanges선언이다.onConfigurationChanged() or ConfigurationLocal.current를 통한 Configuration상태값 수신이 가능하다.Activity재생성을 방지했을 경우, 구성 변경에 따른 리소스 재할당을 개발자가 직접 신경써야한다.Activity재생성을 유도하는걸 권고하고 있다.onConfigurationChanged()의 호출 버그 또한 있어, 더욱 권장하지 않는다.Activity재생성을 유도하는 게 좋은 선택지일 수 있다.