Android - ViewModel을 생성하는 방법

ViewModel은 안드로이드 Lifecycle aware 객체로, Lifecycle을 고려하여 UI 데이터를 저장하고 관리하도록 설계되었습니다. 그렇기 때문에 ViewModel 객체는 ViewModelProvider를 통해서 생성하며, 직접 생성자를 호출하여 생성하지는 않습니다.

ViewModel의 생성자의 인자가 있냐 없냐에 따라서 생성 방법이 달라집니다.

  • ViewModel의 생성자에 인자가 없는 경우 : ViewModelProvider로 VidwModel 객체를 생성할 수 있음.
  • ViewModel의 생성자에 인자가 있는 경우 : ViewModelProvider.Factory 클래스를 구현하면 ViewModelProvider 생성자에 인자를 전달하여 객체를 생성할 수 있음.

인자가 없다면 ViewModelProvider만으로 간단히 객체를 생성할 수 있지만, 인자가 있는 경우는 Factory 클래스를 추가로 구현하여 어떤 인자를 생성자에 전달할지 ViewModelProvider에게 알려줘야 합니다.

예제를 통해서 자세히 알아보겠습니다. 전체 코드는 GitHub - ViewModelFactorySample에 올려두었으니 필요하시면 참고하세요.

1. 인자 없는 ViewModel 객체 생성

아래 클래스는 인자가 없는 ViewModel 클래스입니다.

class MainActivityViewModel : ViewModel() {
    val result = MutableLiveData<String>("init value")
}

Activity에서 ViewModelProvider를 통해 다음과 같이 ViewModel 객체를 생성할 수 있습니다.

val viewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)

ViewModelProvider(this)에서 this는 ViewModelStoreOwner를 의미합니다. Activity가 ViewModelStoreOwner 인터페이스를 구현하고 있기 때문에, Activity에서 this를 사용하시면 됩니다.

2. 인자가 있는 ViewModel 객체 생성

다음 클래스는 MyRepository 객체를 인자로 받는 ViewModel 클래스입니다.

class FirstActivityViewModel(
    private val repository: MyRepository
) : ViewModel() {

    val result = MutableLiveData<String>("init value")

    fun reloadResults() {
        result.value = repository.getResult()
    }
}

Factory class 구현

ViewModelProvider는 ViewModel을 생성할 때 어떤 객체를 인자로 전달해줘야할지 모르니까, 아래와 같은 Factory 클래스를 정의해서 어떤 인자를 생성자에 전달할 지 정의해줘야 합니다.

class ViewModelFactory(private val repository: MyRepository)
    : ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(FirstActivityViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return FirstActivityViewModel(repository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

ViewModel 생성

ViewModel을 생성할 때는, 아래와 같이 먼저 Factory 객체를 생성합니다. 그리고 ViewModelProvider에 Factory를 전달하여 ViewModel을 생성합니다. ViewModelProvider는 내부적으로 위에서 구현한 Factory의 create()메소드를 호출하여 인자가 있는 ViewModel을 생성합니다.

val repository = MyRepository()
val viewModelFactory = ViewModelFactory(repository)

val viewModel = ViewModelProvider(this, viewModelFactory).get(FirstActivityViewModel::class.java)

3. 인자가 없는 AndroidViewModel 객체 생성

AndroidViewModel는 ViewModel인데, App의 Context 정보를 알고 있는 ViewModel입니다. AndroidViewModel 객체도 ViewModelProvider를 통해서 생성해야 합니다.

다음은 간단한 형태의 AndroidViewModel 클래스입니다.

class SecondActivityViewModel(application: Application)
    : AndroidViewModel(application) {

}

다음과 같이 ViewModelProvider으로 ViewModel 객체를 생성할 수 있습니다. ViewModelProvider의 인자로 AndroidViewModelFactory 객체를 함께 전달합니다.

val viewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory(application))
        .get(SecondActivityViewModel::class.java)

4. 인자가 있는 AndroidViewModel 객체 생성

다음은 MyRepository 객체를 인자로 받는 AndroidViewModel 클래스입니다.

class ThirdActivityViewModel(
    application: Application, private val repository: MyRepository
) : AndroidViewModel(application) {

}

Factory class 구현

위에서 구현한 Factory 클래스처럼, Application과 MyRepository 객체를 ApplicationViewModel의 생성자에 전달합니다.

class ViewModelFactory(private val application: Application, private val repository: MyRepository)
    : ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(ThirdActivityViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return ThirdActivityViewModel(application, repository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

ViewModel 생성

ApplicationViewModel도 다음과 같이 Factory 객체를 ViewModelProvider에 전달하여 ViewModel 객체를 생성합니다.

val repository = MyRepository()
val viewModelFactory = ViewModelFactory(application, repository)

val viewModel = ViewModelProvider(this, viewModelFactory)
        .get(ThirdActivityViewModel::class.java)

References

Loading script...

Related Posts

codechachaCopyright ©2019 codechacha