안드로이드의 AAC(Android Architecture Components)를 공부하다 보면, 가장 처음에 나오는 개념입니다.
ViewModel이란?
구글 문서에 보면 아래와 같이 설명이 나와있습니다.
Android 프레임워크는 활동과 프래그먼트 같은 UI 컨트롤러의 수명 주기를 관리합니다. 프레임워크는 특정 사용자 작업이나 완전히 통제할 수 없는 기기 이벤트에 대한 응답으로 UI 컨트롤러를 제거하거나 다시 만들도록 결정할 수 있습니다.
시스템에서 UI 컨트롤러를 제거하거나 다시 만드는 경우, 컨트롤러에 저장된 모든 일시적인 UI 관련 데이터가 삭제됩니다. 예를 들면 앱 활동 중 하나에 사용자 목록이 포함되어 있는데, 구성이 변경되어 활동이 다시 생성되면 새 활동이 사용자 목록을 다시 가져와야 합니다. 데이터가 단순한 경우 활동은 onSaveInstanceState() 메서드를 사용하여 onCreate()의 번들에서 데이터를 복원할 수 있습니다. 하지만 이 접근 방법은 사용자 목록이나 비트맵과 같은 대용량일 가능성이 높은 데이터가 아니라, 직렬화했다가 다시 역직렬화할 수 있는 소량의 데이터에만 적합합니다.
다른 문제는 UI 컨트롤러가 반환하는 데 시간이 걸릴 수 있는 비동기 호출을 자주 해야 한다는 점입니다. UI 컨트롤러는 비동기 호출을 관리해야 하며, 메모리 누수 가능성을 방지하기 위해 호출이 제거된 후 시스템에서 호출을 정리하는지 확인해야 합니다. 관리에는 많은 유지관리가 필요하며, 구성 변경 시 개체가 다시 생성되는 경우 개체가 이미 수행된 호출을 다시 호출해야 할 수 있으므로 리소스가 낭비됩니다.
활동 및 프래그먼트와 같은 UI 컨트롤러의 목적은 기본적으로 UI 데이터를 표시하거나, 사용자 작업에 반응하거나, 권한 요청과 같은 운영체제 커뮤니케이션을 처리하는 것입니다. 또한 UI 컨트롤러에 데이터베이스나 네트워크에서 데이터 로드를 책임지도록 요구하면 클래스가 팽창됩니다. UI 컨트롤러에 과도한 책임을 할당하면 다른 클래스로 작업이 위임되지 않고, 단일 클래스가 혼자서 앱의 작업을 모두 처리하려고 할 수 있습니다. 또한 이런 방법으로 UI 컨트롤러에 과도한 책임을 할당하면 테스트가 훨씬 더 어려워집니다.
UI 컨트롤러 로직에서 뷰 데이터 소유권을 분리하는 방법이 훨씬 쉽고 효율적입니다.
-> 안드로이드 생명 주기를 관리하기 쉽다
-> onSaveInstanceState() 를 사용할 수 있는데, 적절하지 않다
-> 안드로이드 생명 주기를 관리하기 쉽다와 같은 말인데, 상태가 변경될 때 마다 데이터를 관리해줘야 한다. 이 것을 하기 편하다.
-> UI컨트롤러(Activity나 Fragment)에서 모든 것을 다 하려고 하면 복잡해진다 때문에, ViewModel을 쓰는 것이 좋다.
정도로 할 수 있을 것 같습니다.
ViewModel 클래스는 수명 주기를 고려하여 UI 관련 데이터를 저장하고 관리하도록 설계되었습니다. ViewModel 클래스를 사용하면 화면 회전과 같이 구성을 변경할 때도 데이터를 유지할 수 있습니다.
여기에서 핵심 키워드는 아래와 같습니다.
1. 수명 주기를 고려하여 UI관련 데이터를 저장하고 관리하도록 설계되었다.
2. 화면 구성을 회전과 같이 변경할 때도 데이터를 유지할 수 있다.
자, 그렇다면 이 부분을 요약하면 화면이 돌아가고 UI데이터가 변경되도 데이터를 유지하기 위해 사용된다 라고 생각할 수 있는데, 여기까지만 하면, 전혀 이해가 되지 않습니다.
때문에, 이 ViewModel에 대한 것을 그림으로 나타낸 것을 보면 아래와 같이 설명되어 있습니다.
즉 Activity 사이클이 한바퀴 다 돌아갈 때 까지 ViewModelScope의 범위가 지속되는 것이라고 보여집니다.
자, 그렇다면 이 것을 코드에서 보면 어떻게 되는지 알아보겠습니다.
저 생명주기를 보기 위해 액티비티의 생명주기부터 한번 살펴볼게요.
Activity의 생명주기
일단, 액티비티 생명주기부터 한번 볼까요?
Activity 생명주기를 보기 위해 일단 코드를 아래와 같이 작성해보았습니다.
여기에서 앱을 켜면 로그가 어떻게 찍힐까요?
위와 같이 앱이 켜지는 작업이기 때문에, onCreate -> onStart -> onResume 순서로 찍힙니다.
자, 그렇다면 이 때 화면을 뒤집으면 어떻게 될까요?
화면을 뒤집으면 아래와 같이, View가 파괴되고 다시 생성되는 것을 볼 수 있습니다.
여기에서 드는 의문이 아니 뷰가 새로 생기는게 뭐가 문제야? 라고 생각할 수 있습니다.
아래와 같은 문제가 생길 수도 있어요!
한번 볼까요?
간단한 계산기 앱을 만들어봤습니다.
위와 같이 레이아웃을 만들어놓고 xml은 아래와 같이 했습니다.
아래의 플러스와 마이너스 버튼을 누르면 숫자가 올라가도록 구현하였습니다.
Acitivity의 코드를 보면 아래와 같습니다.
당연히 플러스 버튼과 마이너스 버튼을 누르면 위와 같이 숫자가 카운팅 됩니다.
다만 여기서 문제가 뭐냐하면, 여기에서 화면을 뒤집는 순간 저기 있는 3이 0으로 변합니다.
이와 같은 문제점을 해결하기 위해 ViewModel을 사용해주면 됩니다.
글이 길어지니 다음 글에서 계속해보겠습니다.
- 참고
https://developer.android.com/topic/libraries/architecture/viewmodel#samples
'Android Jetpack' 카테고리의 다른 글
Android ViewModel - 3 (Fragment에서 사용) (0) | 2021.12.18 |
---|---|
Android ViewModel - 2 (Activity ViewModel) (0) | 2021.12.18 |
Android View에 대한 접근 - 4 (Databinding with DataClass) (0) | 2021.12.15 |
Android View에 대한 접근 - 3 (databinding) (0) | 2021.12.14 |
Android View에 대한 접근 - 2 (ViewBinding) (0) | 2021.12.11 |