Android/JetPack

AAC - viewModel

봄석 2019. 9. 2. 16:16

AAC(Andorid Architecture Component) - viewModel

 

viewModel알아보기!

안드로이드 아키텍처 컴포넌트 viewModel은 UI관련 데이터를 저장하고 관리하기 위하여 설계되었습니다.

스크린 회전 같은 상태 변화에도 데이터가 보존될 수 있도록 합니다.

 

안드로이드기기를 회전한다면 안드로이드 생명주기는 위 그림의 왼쪽처럼 

화면이 Destroy되고 다시 Create되는 과정을 거치게됩니다.

 

위같은 회전에대하여 간단한 데이터같은 경우 onSaveInstanceState()메소드를 이용하여 저장하고

다시 onCreate()에서 다시 데이터를 받을 수 있지만,

serialize가 가능한 간단한데이터만 가능합니다. bitmap같은 많은양에 데이터는 부적합합니다.

또한 화면회전의 상태변화로 인해서 객체를 재생성해야하는경우, 이미 만들어진객체를 재생성해야하므로 리소스낭비가 심합니다.

 

또 다른 대안으로는 Retained Fragment 를 사용하는 방법도 있습니다.

UI가 없는 Fragment를 사용하여 UI에 필요한 데이터를 관리하고, 이 프래그먼트를 

setRetainInstance(true)를 사용하여 설정함으로서 , 액티비티 파괴시에도  

프레그먼트를 메모리에 유지시키는 방법입니다.

이방법을 쓰면 onDetach, onAttach등을 반복하지 않습니다.

 

하지만 일정한 범위를 넘어섰을때 또다른 문제를 다뤄야했습니다.

이곳이 데이터를 보관하기에 적합한 곳인가? 혹은 오버-엔지니어링이 아닐까?라는 논쟁의 여지가 존재했습니다.

 

아키텍처 컴포넌트의 ViewModel은 개발자에게 전가된 이러한 고민들을 근본적으로 해결합니다. 

viewModel은 화면회전에도 스코프가 일관되게 유지되는것을 볼 수 있습니다(위  그림의 오른쪽)

 

 

viewModel의 장점

  • viewModel은 액티비티 스코프의 싱글톤객체처럼 사용할수 있습니다.
    • 프래그먼트 사이에서 viewModel을 이용하여 데이터를 쉽게 공유할 수 있습니다.
    • 더이상 프래그먼트 중개자로 액티비티를 사용하지않아도됩니다.(액티비티의 역할수행을 덜을수있음)
  • 위에서 말한 화면회전 같은 부분문제를 해결합니다.

 

 

 

viewModel 더 자세히 알아보기

  • viewModel 라이브러리는 내부적으로  프래그먼트를 사용합니다
    • 최초  viewModel을 생성할 때 , ViewModelProvider는 HolderFragment라 명명된프래그먼트를 생성하고
      • 이 프래그먼트에는 setRetainInstance(true)가 설정됩니다.
    • viewModel은 유보된 프래그먼트(RetainFragment)의 연장선이라 할 수 있습니다.
  • viewModel은 추상클래스(abstract)로 상속하는것만으로 viewModel을 만들 수 있습니다 .
    • 추상클래스이므로 객체를 그냥 생성할수 없습니다.
    • ViewModelProvider를 통해 객체를 생성해주어야합니다.
class DisplayViewModel(val mainVm: MainViewModel) : ViewModel()

 

  • 생명주기 함수 onCleared()가 존재합니다.
  • 커스텀 생성자를 가지려면, ViewModel은 ViewModelProvider.Factory 인터페이스를 사용해야합니다.
//위코드의 DisplayViewModel을 생성하기위한 팩토리클래스
class DisplayViewModelFactory(val mainViewModel: MainViewModel) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return modelClass.getConstructor(MainViewModel::class.java).newInstance(mainViewModel)
    }
}
val factory = DisplayViewModelFactory(mainVm)
    val displayVm = ViewModelProviders.of(this, factory).get(DisplayViewModel::class.java)

 

 

viewModel 사용시에 주의사항

  • viewModel내부에 액티비티, 프레그먼트, 뷰에 대한 컨텍스트를 저장해서는 안됩니다.
    • viewModel의 수명주기는 외부에 존재하기때문에 , 메모리 릭의 원인이 될 수 있습니다.
    • ApplicationContext 는 상관없습니다. AndroidViewModel클래스도 제공하고 있습니다.
  • viewModel은 기기의 구성이 변경될때만 유지됩니다.
    • 백버튼이나 , 최근목록에서 앱을 종료했을때는 어떠한 처리도 기대할 수 없습니다.
  • A라는 액티비티에서 사용하는 viewModel을  B 액티비티에서 viewModel에 저장된 값을 사용하고 싶다면 ?

  • 단일 액티비티에서 2개이상의 프래그먼트 사이 데이터를 공유할때
    • viewModel을 생성할때 프래그먼트의 scope를 사용하는것이아닌 액티비티의 scope를 전달하는것이 좋습니다.