회전 · 다크모드 전환 · 언어 변경 등이 일어나면 Activity를 파괴하고 즉시 재생성한다.
왜 멀쩡한 화면을 부수나
구성이 바뀌면 써야 할 리소스가 통째로 달라진다
- layout-land/ — values-night/ values-ko/ drawable-xxhdpi/
안드로이드는 '새 구성에 맞는 리소스를 처음부터 다시 로드' 하는 가장 단순하고 확실한 방법으로 재생성을 택했다
onPause → onStop → onSaveInstanceState → onDestroy
↓
onCreate(savedInstanceState) → onStart → onRestoreInstanceState → onResume
대가는 상태 유실
Activity 멤버 변수에 담아 둔 모든 것이 사라진다
- 사용자가 긴 폼을 절반 채우고 회전 → 입력이 다 날아간다
해법은 층이 있다
① ViewModel 회전에 살아남는다. 목록 · 진행 중 작업 · 화면 상태
② SavedStateHandle 프로세스 죽음까지 넘는다. 검색어 · 선택 항목 id
③ DB(SSOT) 큰 데이터는 어느 쪽에도 담지 않고 다시 로드한다
configChanges로 막는 것은 대개 잘못이다
<activity android:configChanges="orientation|screenSize|keyboardHidden" />
재생성이 일어나지 않고 onConfigurationChanged() 만 불린다
왜 위험한가
- 새 구성에 맞는 리소스가 자동으로 적용되지 않는다
- (layout-land 가 무시된다 · 다크모드 색이 안 바뀐다)
- 결국 직접 갱신 코드를 써야 하고 빠뜨린 곳이 버그가 된다
- 프로세스 죽음은 여전히 못 막는다 — 근본 해결이 아니다
정당한 사례는 거의 없다 (전체화면 동영상 재생 정도)
개발 중 확인법
- 에뮬레이터에서 회전 (Ctrl+F11)
- 개발자 옵션 → 가로 세로 강제 전환
- 다크모드 토글도 구성 변경이다 — 회전만 테스트하면 절반만 본 것
면접 함정
- ❌ "ViewModel이 있으니 구성 변경은 해결됐다" → 스크롤 위치·입력 중 텍스트 같은 UI 요소 상태는 별도로 저장해야 한다.
- ❌ "configChanges를 쓰면 성능이 좋다" → 리소스 재적용을 스스로 떠안는 것이다.
어떤 것이 구성 변경인가
-
화면 회전 · 접이식 폰 펼침
-
다크모드 전환
-
언어 변경
-
글꼴 크기 변경 · 디스플레이 크기 변경
-
멀티윈도우 진입/이탈 · 창 크기 변경
-
키보드 연결/해제
-
회전만 테스트하는 것으로는 절반도 못 본다
Compose는 어떻게 살아남나
@Composable
fun Screen() {
var count by rememberSaveable { mutableStateOf(0) } // 구성 변경 생존
var focus by remember { mutableStateOf(false) } // 사라진다 (그래도 됨)
}
Compose 는 Activity 가 재생성되면 컴포지션도 처음부터 다시 만든다
- remember 는 사라진다
- rememberSaveable · ViewModel 만 남는다
"이 값이 회전 후에도 있어야 하나?" 를 컴포저블마다 판단한다
리소스 한정자가 자동으로 갈린다
- res/layout/ — 기본
- res/layout-land/ — 가로
- res/values-night/ — 다크
- res/values-ko/ — 한국어
- res/drawable-xxhdpi/ 밀도
재생성 덕분에 이 전환이 자동이다 — configChanges 로 재생성을 막으면 이 자동화를 스스로 포기하는 것이다