안드로이드 컴포넌트의 생명 주기에 따라 데이터가 유실되지 않도록 하기 위해 ViewModel을 사용하는 것이 일반적이지만, 문득 구성 변경(Configuration Change)으로 인해 Activity가 파괴되는데도 어떻게 ViewModel이 유지될 수 있을까? 하는 궁금증이 들었습니다.
ViewModel이 어떻게 상태를 관리하고 구성 변경 시에도 유지될 수 있는지 이해하기 위해 내부 코드를 직접 분석하고 정리한 내용을 공유하겠습니다. 또한, ViewModel의 개념과 사용 시 고려해야 할 사항들도 함께 정리하겠습니다.
ViewModel이란?
- 구성 변경이 발생해도 데이터를 유지하도록 설계된 컴포넌트입니다.
- Activity나 Fragment보다 생명 주기가 깁니다.
- 하지만 앱이 종료되면 ViewModel도 함께 종료됩니다.
- 예시: 화면 회전 시에도 UI 상태를 유지하는 데 활용됩니다.
ViewModel의 상태 유지
ViewModel을 활용하면 구성 변경 시에도 데이터를 유지할 수 있지만, 백그라운드에서도 데이터를 보존하려면 SavedStateHandle을 활용해야 합니다.
class MyViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
private val _count = savedStateHandle.getLiveData("count", 0)
val count: LiveData<Int> get() = _count
fun increaseCount() {
_count.value = _count.value?.plus(1)
savedStateHandle.set("count", _count.value)
}
}
- SavedStateHandle을 이용하면 프로세스 종료 후 복원 시에도 상태를 유지할 수 있습니다.
ViewModel 사용 시 유의사항
1. ViewModel의 목적은 구성 변경 시 상태 유지
- 화면 회전 등으로 인해 Activity 또는 Fragment가 재생성되더라도 데이터를 유지할 수 있습니다.
- 하지만 앱이 종료되면 ViewModel도 함께 종료됩니다.
2. 영구적인 데이터 저장에는 적합하지 않음
- ViewModel은 메모리 내에서만 데이터를 관리하므로 영구 저장소로 활용하면 안 됩니다.
- 데이터를 영구적으로 저장하려면:
- 로컬 저장소(Room, SharedPreferences 등)
- 원격 서버(Firebase, API 서버 등)
- 위와 같은 저장 매체를 활용해야 합니다.
3. Activity Context 참조 금지 (메모리 누수 방지)
- ViewModel은 Activity보다 오래 살아남으므로 Activity의 Context를 직접 참조하면 메모리 누수가 발생할 수 있습니다.
- 만약 Context가 꼭 필요하다면 ApplicationContext를 사용해야 합니다.
class MyViewModel(application: Application) : AndroidViewModel(application) {
private val context = getApplication<Application>().applicationContext
}
- AndroidViewModel을 사용하면 안전하게 ApplicationContext를 참조할 수 있습니다.
4. UI에 대한 의존성을 최소화해야 함
- ViewModel은 UI와 독립적이어야 하며, UI 관련 로직을 포함해서는 안 됩니다.
- UI 상태는 LiveData 또는 StateFlow 등을 통해 관리하고, UI에서 이를 구독하는 방식이 권장됩니다.
5. ViewModel을 다른 클래스, 함수에 전달하지 않기
- ViewModel 인스턴스는 시스템에서 관리되므로, 다른 일반 클래스나 함수에 전달하면 예기치 않은 문제가 발생할 수 있습니다.
- Activity나 Fragment 등 UI 시스템에 가깝게 배치하는 것이 바람직합니다.
ViewModelStore란?
ViewModelStore는 ViewModel 인스턴스를 저장하고 관리하는 역할을 하는 객체입니다. 즉, ViewModel을 생성하고 유지하며, 구성 변경 시에도 동일한 ViewModel을 반환할 수 있도록 도와주는 저장소입니다.
ViewModelStore의 역할
- ViewModel을 저장하고 관리
- ViewModelProvider가 새로운 ViewModel을 생성하거나 기존 ViewModel을 ViewModelStore에서 찾아 반환할 수 있도록 합니다.
- 구성 변경 시에도 ViewModel을 유지
- Activity가 화면 회전 등으로 파괴되더라도 ViewModelStore는 유지됩니다.
- 새로 생성된 Activity가 기존 ViewModelStore를 참조하여 기존 ViewModel을 다시 사용합니다.
- 필요 없을 때 ViewModel을 정리
- Activity가 완전히 종료되면, ViewModelStore도 제거되면서 ViewModel도 함께 정리됩니다.
ViewModelStore 내부 동작 분석
1. viewModels() 함수와 ViewModelStore의 관계
위 코드는 내부적으로 viewModels() 확장 함수를 사용하여 ViewModel을 초기화합니다. 해당 함수는 다음과 같은 과정을 거칩니다.
viewModels 안으로 들어가보면, 아래와 같은 코드가 나옵니다.
- viewModelStore를 이용해 ViewModel을 가져오며, 기존에 생성된 ViewModel이 있다면 이를 반환합니다.
- ViewModelStoreOwner를 사용하여 현재 Fragment 또는 Activity의 ViewModelStore를 참조합니다.
여기서 다시 viewModelStore 코드 안으로 들어가 보겠습니다.
2. ViewModelStore의 내부 동작
- ViewModelStore는 내부적으로 map을 사용하여 ViewModel을 저장하고 관리합니다.
- put()을 통해 새로운 ViewModel을 저장하고, 기존 ViewModel이 있다면 onCleared()를 호출하여 정리합니다.
- clear()를 호출하면 모든 ViewModel이 제거됩니다.
즉, ViewModelStore를 유지하면서 기존 ViewModel을 재사용하는 구조입니다.
마무리
- ViewModelStore는 ViewModel을 저장하고 관리하는 역할을 합니다.
- Activity가 파괴되더라도 ViewModelStore가 유지되면 ViewModel을 계속 사용할 수 있습니다.
- Activity가 완전히 종료되면 ViewModelStore도 삭제되며, ViewModel도 정리됩니다.
- ViewModelStore 내부적으로 클래스를 키로 사용하여 Activity/Fragment별로 ViewModel을 구별합니다.
참고: https://developer.android.com/reference/androidx/lifecycle/ViewModelStore
ViewModelStore | API reference | Android Developers
androidx.appsearch.builtintypes.properties
developer.android.com
'Android > Android Core' 카테고리의 다른 글
[Android/Kotlin] Retrofit에서 인터페이스를 활용한 API 요청 처리 원리 (0) | 2025.03.12 |
---|---|
[Android] Activity 생명주기 정리 (0) | 2025.02.24 |
[Android/Kotlin] 비상 사운드 효과 구현: 강제 볼륨 조절 (0) | 2024.12.13 |
[Android/Kotlin] 뒤로가기 기능을 구현하는 방법: OnBackPressedDispatcher 활용법 (0) | 2024.12.03 |
[Android/Kotlin] Kakao Map V2: 특정 좌표를 모두 화면에 표시하기 (0) | 2024.12.02 |