[Android JetPack] ViewModel이란 무엇인가?

JJAE WON·2021년 9월 12일
3

Android JetPack

목록 보기
1/3
post-thumbnail
post-custom-banner

들어가기전에,,,

ViewModel에는 MVVM 패턴 에서 언급되는 ViewModel과,
테스트와 유지보수가 쉬운 앱을 만들 수 있도록 도와주는 AAC(Android Architecture Components) ViewModel, 두가지가 있다.

  1. MVVM 패턴의 ViewModel
    View와 Model 사이의 매개체 역할을 하고 View에 보여지게 되는 데이터를 가공하는 역할을 한다.

  2. AAC의 ViewModel
    앱의 Lifecycle을 고려하여 UI 관련 데이터를 저장하고 관리하는 역할을 한다.


구글에서는 MVVM 패턴을 사용하여 앱을 만들 것을 권장하고 있고
MVVM의 ViewModel을 구현할 때 AAC ViewModel을 사용해서 구현하는 것이 좋다.

이전 포스팅 에서 언급한 LiveData와 함께 사용되는 ViewModel은 AAC의 ViewModel이다. 오늘은 AAC ViewModel에 대해 더 자세하게 알아보자!!😎


ViewModel이란﹖

Activity와 fragment와 같은 UI 컨트롤러의 로직에서 데이터를 다루는 로직을 분리하기 위해 등장한 Android JetPack 라이브러리이다.

왜 두가지를 분리해야 할까?

  1. UI 컨트롤러의 목적
    데이터를 표시해주거나, 사용자가 어떤 작업을 했을때 반응을 보여주거나, 권한 요청과 같은 OS커뮤니케이션을 처리하는 것이 UI컨트롤러의 목적이다.

    따라서, UI 컨트롤러에서 데이터를 다루는 로직을 책임지게 되면 많은 유지보수가 필요한 비동기 호출과 같은 작업들을 해야하기 때문에 UI 컨트롤러에 과도한 책임이 생기게 된다.

  2. 데이터 손실 방지
    UI 컨르롤러에서는 생명주기에 따라 앱이 활동중에 제거될 때마다 데이터를 저장시키고
    , 다시 생성될 때마다 데이터들을 다시 불러와야 한다.

데이터를 복원하기 위해 onSaveInstanceState() 메서드를 사용하는 방법은 작은 용량의 데이터에만 적합하고 데이터가 커지게 되면 적합하지 않다.

ViewModel의 생명주기

Activity의 생명주기와 상관없이 살아있다면 데이터가 쭉 유지되면 데이터의 손실을 방지할 수 있을 것이다. 그래서 ViewModel은 Activity의 생명주기 보다 긴 수명을 가지는 생명주기를 갖게 된다.
ViewModel의 Scope(생명주기의 범위)는 ViewModel을 가져올 때 ViewModelProvider에 의해 결정 된다.

그림을 보면 Activity가 생성되고 rotated가 되고 , finish되면서 다양한 수명 주기 상태를 갖게 되는데 그 때 동안 ViewModel의 생명주기는 바뀌지 않는다.

🤔 그렇다면 ViewModel은 언제 종료되는가??
-> Activity가 더이상 사용하지 않는 상태가 되었을 때, onCleared() 를 호출하려 내부 데이터를 초기화하고 파괴한다.


ViewModel 프로세스

ViewModel을 구현하기 위해선 ViewModelProvider의 도움을 받아야 한다. 위 그림과 함께 구조를 살펴보자

ViewModelProvider (ViewModelStoreOwner owner, ViewModelProvider.Factory factory)
  • 첫번째 매개변수ViewModelStoreOwner인데 ViewModelStore의 정보를 가지고 온다.
    ViewModelStoreViewModel이 어떤 Activity와 연관이 있나를 알고 있는 얘로
    Activiy나 Fragment를 넣어주면 된다.
  • 두번째 매개변수ViewModelProvider.Factory로 실질적으로 ViewModel 인스턴스를 생성하는 역할을 하는 factory를 넣어 주면 된다. (여기서 알 수 있듯이 ViewModel은 팩토리패턴으로 구현된다!)

ViewModel 구현하기

1. 클래스 정의

  • MyViewModel.kt
  class MyViewModel : ViewModel(){
    private val users: MutableLiveData<List<User>> by lazy {
        MutableLiveData<List<User>>().also {
            loadUsers()
        }
    }

    fun getUsers(): LiveData<List<User>> {
        return users
    }

    private fun loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
  }

2. ViewModel 객체 생성

2-1.

Android Devlepers 에 나와있는 방법으로 커스텀은 불가능하다.

  class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
  
          val myViewModel: MyViewModel by viewModels()

        })
    }
}

2-2. ViewModelProvider 사용

gradle에 lifecycle에 대한 의존성을 추가해 주어야 사용할 수 있다.

  class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
	   val myViewModel = ViewModelProvider(this).get(MyViewModel::class.java)
        })
    }
}

2-3. ViewModelProvider.NewInstanceFactory 사용

안드로이드에서 제공해주는 팩토리 클래스이다. ViewModel에 파라미터가 없을 경우 사용하면 되고 의존성 주입은 필요 없다.

  class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
	    val myViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())
  			   .get(MyViewModel::class.java)
        })
    }
}

2-4. ViewModelProvider.Factory 사용

ViewModel에 파라미터가 있을 경우, 직접 Factory 클래스를 만들어서 사용하는 방법이다.
1번에 String 파라미터가 있다고 잠깐 가정하자~

  • ViewModelFactory.kt
  class ViewModelFactory(private val param: String) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return if(modelClass.isAssignableFrom(MyViewModel::class.java)){
            MyViewModel(param) as T
        } else{
            throw IllegalArgumentException()
        }
    }
}
}
  • MainActivity
  class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
	    val myViewModel = ViewModelProvider(this,ViewModelFactory("jaewon")
  				.get(MyViewModel::class.java)
        })
    }
}

상황에 맡게 ViewModel 객체를 생성해서 사용하면 된다!!!!!



참조
profile
안드왕 찐천재가 되고싶습니다.
post-custom-banner

0개의 댓글