본문 바로가기
개발/Android

[Android] ACC ViewModel이란? - 정의, 사용법, 주의할점

by tempus 2022. 4. 16.
반응형

AAC ViewModel이란?

우리는 안드로이드 앱을 설계할 때 MVVM 패턴을 많이 사용합니다. 오늘은 이 MVVM 패턴에서 빠질 수 없는 요소인 ViewModel을 쉽게 구현해주는 AAC의 ViewModel에 대해 알아보려고 합니다. AAC ViewModel을 사용하면 MVVM을 좀 더 쉽게 구현할 수 있습니다. (앞으로 나올 ViewModel은 AAC의 ViewModel을 의미)

 

ViewModel은 액티비티와 프래그먼트에서 사용되는 UI 관련 데이터를 보관하고, 관리하기 위해 디자인되었습니다.

 

이전에 액티비티가 재생성될 때 데이터를 유지할 수 없었습니다. (예 : 화면 회전) 하지만 ViewModel은 액티비티가 재생성되는 상황에서도 ViewModel 인스턴스를 유지함으로써 데이터를 안전하게 다룰 수 있습니다.

 

왜냐하면 ViewModel의 생명주기는 그림과 같기 때문입니다.

 

 

ViewModel은 액티비티 스코프의 싱글톤 객체처럼 사용할 수 있습니다. 이때문에 해당 Activity 위에 있는 Fragment들 사이에서 ViewModel을 이용해 데이터를 쉽게 공유할 수 있습니다. ViewModel은 Activity가 완전히 종료되는 시점에 종료됩니다. 이 때 호출되는 함수가 onCleared()입니다.

 

정리하면 ViewModel을 사용해 다음과 같은 이점을 얻을 수 있습니다.

  1. Activity 책임을 줄여줄 수 있다.
  2. Fragment 사이에서 데이터를 쉽게 공유할 수 있다.

 

ViewModel 사용법

ViewModel은 추상 클래스이며 이 클래스를 상속하는 것만으로 ViewModel을 만들 수 있습니다.

class SimpleViewModel : ViewModel() {

    override fun onCleared() {
        super.onCleared()
        //여기서 ViewModel 종료 시 메모리 해제할 친구들을 해제해주자
    }
    
}

 

그리고 Activity에서는 다음과 같이 사용하면 됩니다.

class MainActivity : AppCompatActivity() {

    private lateinit var simpleViewModel: SimpleViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        simpleViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(SimpleViewModel::class.java)
    }
}

 

ViewModelProvider는 해당 Activity와 ViewModel을 연결시켜주는 역할을 한다. 과정은 아래와 같습니다.

 

  1. ViewModelProvider를 통해 ViewModel 인스턴스를 요청
  2. ViewModelProvider 내부에서는 ViewModelStoreOwner를 참조하여 ViewModelStore를 가져옴
  3. ViewModelStore에게 이미 생성된 ViewModel 인스턴스를 요청
  4. 만약 ViewModelStore가 필요한 ViewModel 인스턴스를 가지고 있지 않다면 Factory를 통해 ViewModel 인스턴스 생성
  5. 생성한 ViewModel 인스턴스를 ViewModelStore에 저장하고 ViewModel 인스턴스를 클라이언트에게 반환

 

  • ViewModel은 ViewModelStore라는 객체에서 관리합니다. (내부적으로 HashMap<String, ViewModel>를 두어 관리)
  • ViewModelStore 객체는 ViewModelStoreOwner가 관리합니다. (ViewModelStoreOwner는 interface이고 ComponentActivity와 Fragment클래스가 이를 구현)

즉, ViewModel을 생성하기 위해서는 Fragment나 Activity가 필요하다는 것을 알 수 있습니다.

 

ViewModelProvider의 내부 구조는 다음과 같습니다.

public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
    this(owner.getViewModelStore(), factory);
}
simpleViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(SimpleViewModel::class.java)

이 부분을 다시 보면 this 부분은 ViewModelStoreOwner가 필요하므로 이를 구현할 Fragment나 Activity가 필요하고 실질적으로 ViewModel을 생성해줄 Factory가 필요합니다.

NewInstanceFactory() 같은 경우에는 안드로이드가 기본적으로 제공해주는 팩토리 클래스이고 생략이 가능합니다. get부분은 생성하고자 하는 ViewModel 클래스 타입을 넣어주면 됩니다.

 

하지만 나는 위에 방식보다는 by viewModels()를 통해 생성하는 것을 더 선호합니다. 하기 위해서는 아래의 종속성을 프로젝트에 추가해주어야 합니다.

android {
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

implementation "androidx.fragment:fragment-ktx:1.3.6"

 

그러면 아래와 같이 좀 더 깔끔하게 사용할 수 있습니다.

class MainActivity : AppCompatActivity() {
    private val simpleViewModel by viewModels<SimpleViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

    }
}

 

Fragment 간에 데이터 공유

Fragment 간 데이터 공유는 by activityViewModels()를 사용하면 됩니다. 이를 사용하면 Fragment가 붙은 Activity에 ViewModel이 종속됩니다. (단, by activityViewModels()는 Fragment에서만 호출이 가능하다.)

 

아래는 공식 홈페이지의 예제 중 하나입니다.

class ListFragment : Fragment() {

    private lateinit var itemSelector: Selector

    // Use the 'by activityViewModels()' Kotlin property delegate
    // from the fragment-ktx artifact
    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        itemSelector.setOnClickListener { item ->
            // Update the UI
        }
    }
}

 

ViewModel 사용 시 주의할 점

  1. ViewModel은 View, Fragment, Activity에 대한 Context를 저장해서는 안됩니다. ViewModel의 생명주기는 Activity에 종속되지 않기 때문에 이미 destroy된 component로 인해 메모리 릭이 발생할 수 있습니다. (단, Application Context를 저장하는 것은 문제가 되지 않는다.) ⇒ Application Context를 참조하고 싶다. 그러면 AndroidViewModel을 사용하면 됩니다.
  2. (권장사항) Activity/Fragment에 하나의 ViewModel만을 사용하는 것을 권장합니다. ⇒ 복잡도가 높아지기 때문에 하나의 ViewModel에 여러 LiveData를 다루는게 더 효율적입니다.

 

 

반응형

댓글


loading