ViewModel 거짓: 현대 Android 앱이 취약한 이유
Source: Dev.to

우리는 모두 그런 경험을 해봤습니다. 최신 Jetpack 라이브러리를 사용해 아름다운 앱을 만들었고, MVVM을 적용했으며 코드도 깔끔하고 ViewModel이 데이터를 담당하고 있습니다. 기기에서 테스트해 보니 완벽히 동작합니다. 마치 “현대 안드로이드 개발자”가 된 듯한 기분이죠.
그런데 어느 순간 사용자가 리뷰를 남깁니다: “앱이 무작위로 내 데이터를 잃어버려요”
로그를 확인해 보니 크래시가 없습니다. 재현을 시도해도 아무 일도 일어나지 않죠. 사용자가 잘못했다고 생각하기 시작하지만, 그렇지 않습니다. 여러분의 앱은 현대 아키텍처가 알려주지 않은 프로세스 종료라는 조용한 실패에 직면한 것입니다.
ViewModel의 편안함
수년간 구글은 ViewModel이 Activity 생명주기 문제의 해답이라고 말했습니다. 화면이 회전하면 Activity는 사라지지만 ViewModel은 살아남는다는 것을 배웠죠.
우리는 안심했습니다. 모든 것을 ViewModel에 넣기 시작했습니다: 사용자 프로필, 검색 결과, 폼 데이터 등. 앱이 “실행 중”인 한 데이터는 안전하다고 가정했죠.
그것이 거짓이었습니다.
실제 상황에서 일어나는 일
현실 세계에서는 사용자가 앱에만 머무르지 않습니다. 인스타그램으로 전환하고, 50 MB 4K 사진을 찍고, 무거운 게임을 합니다.
그럴 때 Android OS는 백그라운드에 있는 여러분의 앱을 보고 “RAM이 필요해.” 라고 판단하고 즉시 앱의 프로세스를 종료합니다.
사용자가 다시 돌아오면 Android는 친절하게 Activity를 다시 생성해 줍니다. 하지만 메모리에 있던 ViewModel 상태는? 완전히 새로워집니다. 메모리에 있던 모든 변수는 사라지고 null이 되며, 앱은 엉망이 됩니다.
옛 방식은 정직했다
ViewModel이 나오기 전에는 onSaveInstanceState가 있었습니다.
오랫동안 개발해 온 사람이라면 그 고통을 기억할 겁니다. 모든 변수를 Bundle에 직접 넣고 onCreate에서 다시 꺼내야 했죠. 보일러플레이트가 많고 Activity가 커지며 실수하기 쉬웠습니다.
하지만 한 가지 강점이 있었습니다: 작동한다는 것. OS가 Bundle을 강제하므로 앱은 자연스럽게 프로세스 종료에 대비할 수 있었습니다. 무엇이 저장되고 복원되는지 정확히 알 수 있었죠.
ViewModel이 등장하면서 우리는 한숨을 쉬었습니다. 데이터를 이 반짝이는 새 컨테이너에 옮기고 Bundle은 잊었습니다. “ViewModel이 생명주기를 다루니 이제 끝이야.” 라고 생각했지만, 중요한 사실을 놓쳤습니다:
ViewModel은 구성 변경은 견디지만 프로세스 종료는 견디지 못합니다.
SavedStateHandle의 등장
몇 년 전, 구글은 우리 모두가 데이터를 잃고 있다는 사실을 깨달았습니다. 그 해결책이 SavedStateHandle이었습니다.
취약한 방법 (프로세스 종료 시 데이터 사라짐)
class ProfileViewModel : ViewModel() {
// This is just a variable in RAM.
// If the OS kills the process, this is wiped.
var userId: String? = null
}
견고한 접근법 (데이터 유지)
class ProfileViewModel(private val state: SavedStateHandle) : ViewModel() {
// This is backed by the system Bundle.
// Even if the process dies, "userId" stays safe.
val userId: LiveData = state.getLiveData("user_id")
fun initUser(id: String) {
state["user_id"] = id
}
}
마무리 생각
견고한 앱을 만든다는 것은 최신 라이브러리를 사용하는 것이 아니라 Android OS가 실제로 어떻게 동작하는지를 존중하는 것입니다. 메모리를 믿는 것을 멈추고 SavedStateHandle을 신뢰한다면, 사용자는 데이터를 기억해 주는 앱에 감사할 것입니다.
라이브러리와 모범 사례는 매년 바뀔지 모르지만, Android OS가 메모리를 관리하는 방식은 변하지 않습니다. 시스템이 RAM을 회수해야 할 때를 제어할 수는 없지만, 그때 우리 앱이 어떻게 복구할지는 제어할 수 있습니다.