본문 바로가기
Android

[Android] AAC - ViewModel

by Saerong2 2020. 10. 2.

Google I/O 2017에서 발표한 JetPack의 Android Architecture Components는 안드로이드 개발자들에게 테스트와 유지보수가 편리한 앱을 작성할 수 있도록 도와주고자 만든 라이브러리입니다.

이번 글에서는 AAC의 여러 아키텍처 컴포넌트 중에서 ViewModel에 대해서 정리해보려고 합니다.

 

# AAC ViewModel의 배경

시스템에서 UI를 제거하거나 다시 만들면 저장되어 있던 UI 관련 데이터는 모두 사라지게 됩니다. 대표적인 예로, 화면을 회전시키게 되면 회전한 뷰를 다시 그려야하기 때문에 기존의 액티비티는 제거되고 새로운 액티비티가 생성됩니다. 이때, 액티비티 내의 데이터는 액티비티의 생명주기를 따르기 때문에 화면 회전과 함께 데이터가 모두 날아가게 됩니다.

만약 회원가입 폼을 작성하다가 화면을 돌렸더니 열심히 입력한 데이터가 다 날아갔다면 너무 속상하겠죠. 따라서 더 나은 사용자 경험을 제공하기 위해서는 데이터를 별도로 저장해 두었다가 새롭게 생성된 뷰에 다시 뿌려주어야 합니다. 하지만 액티비티나 프래그먼트 같은 UI 컨트롤러(액티비티, 프래그먼트)에서 직접 DB를 얻어온다면 하나의 클래스가 너무 커지며 많은 일을 하게 됩니다. 이는 복잡성을 높이고 테스트를 어렵게 만드는 원인이 되죠. 여기서, UI 컨트롤러에서 데이터 소유에 대한 로직을 분리함으로써 데이터를 효율적으로 다룰 수 있는 한 가지 방법이 AAC의 ViewModel 입니다.

 

 

# AAC ViewModel

AAC ViewModel은 수명 주기를 고려하여 UI 관련 데이터를 저장합니다. 안드로이드 프레임워크에서는 액티비티나 프래그먼트 등의 뷰를 시스템이 관리합니다. 개발자는 단지 뷰의 LifeCycle 에 따라 시스템에서 호출하는 콜백함수를 이용하여 액티비티, 프래그먼트 등을 관리할 수 있습니다. 액티비티 생명주기에 대해서 잘 모르신다면 이 글을 참고해주세요.

 

위의 그림은 디바이스를 회전시켜서 액티비티가 회전되는 경우의 생명주기를 나타낸 것입니다. 회전에 따라 기존의 액티비티는 제거되고 새로운 액티비티가 생성됩니다. 하지만 뷰에 뿌려질 데이터는 ViewModel에서 관리되기 때문에 액티비티의 생명주기에 따라 데이터가 손실되지 않고 새롭게 생성된 액티비티에 곧바로 기존의 데이터를 뿌려줄 수 있습니다.

 

 

# 그럼 AAC ViewModel의 생명주기는 어떻게 결정되나요?

AAC ViewModel은 ViewModelProvider에 요청을 통해서 생성됩니다. 만약 기존에 만들어진 ViewModel의 인스턴스가 있다면 ViewModelStore에 저장되어 있는 ViewModel 인스턴스를 사용하고 인스턴스가 없다면 ViewModelFactory를 통해서 새로운 ViewModel 객체를 생성합니다. 위의 그림을 보면, ViewModel이 액티비티나 프래그먼트와 별도의 생명주기를 갖는 다는 것은 알겠는데 그렇다면 ViewModel의 생명주기는 어떻게 결정될까요?

ViewModel 객체는 보통 액티비티나 프래그먼트의 OnCreate( )에서 생성합니다. ViewModelProvider를 통해서 생성하며, 생성시 ViewModelProvider에게 전달하는 LifeCycle로 생명주기가 지정이 됩니다. 따라서 해당 생명주기가 끝나기 전까지는 계속 메모리에 남아있게 됩니다.

 

 

# 주의사항

ViewModel은 오직 UI에 뿌려줄 데이터를 관리하기 위한 목적의 Component이며 UI 컨트롤러와 별도의 생명주기를 가집니다. 따라서 ViewModel에서 뷰에 직접 접근하거나, 액티비티나 프래그먼트를 참조하는 등의 구현은 바람직하지 않습니다. Garbage Collector의 "Mark and Sweep" 을 생각해보면, 참조되지 않는 객체들은 모두 GC의 대상이 되어 메모리에서 해제되는데 별도의 생명주기를 갖는 ViewModel에서 쓰이지 않아서 메모리에서 사라져야 할 액티비티나 프래그먼트 등을 여전히 참조하고 있다면 메모리 누수가 발생하게 됩니다. 따라서 시스템의 서비스와 같은 것을 사용하기 위해 context가 필요하다면, Application의 생명주기를 따르는 Application Context를 사용해야 합니다.

댓글