ViewModel을 생성하는 방법

최희창·2022년 6월 12일
0

ViewModelProvider

  • ViewModelProviders 클래스는 Deprecated 되었습니다.
  • 그래서 ViewModelProvider를 통해 ViewModel 객체를 생성합니다.

1. 파라미터가 없는 ViewModel - Lifecycle Extensions

  • androidx.lifecycle의 lifecycle-extensions 모듈을 가져와서 사용해야 한다.
dependencies {
    implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
}
class MainActivity : AppCompatActivity() {
 
    private lateinit var viewModel: NoParamViewModel
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        /* use ViewModelProvider's constructor provided from lifecycle-extensions package */
        noParamViewModel = ViewModelProvider(this).get(NoParamViewModel::class.java)
    }
}
  • ViewModelProvider 생성자에 this를 포함해주고, get() 메서드 내에 생성하고자 하는 뷰모델 클래스 타입을 넣어주면 됩니다.
  • this는 ViewModelStoreOwner 타입이기 때문에 Activity나 Fragment를 넣어주시면 됩니다.

2. 파라미터가 없는 ViewModel - ViewModelProvider.NewInstanceFactory

  • NewInstanceFactory는 안드로이드가 기본적으로 제공해주는 팩토리 클래스이며, ViewModelProvider.Factory 인터페이스를 구현하고 있습니다.
  • 따라서 ViewModel 클래스가 파라미터를 필요로 하지 않거나, 특별히 팩토리를 커스텀할 필요가 없는 상황에서는 1번 or 2번 방법을 사용하면 됩니다.
  • 따로 dependency 추가가 필요하지 않습니다.
        noParamViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())
            .get(NoParamViewModel::class.java)

3. 파라미터가 없는 ViewModel - ViewModelProvider.Factory

  • 직접 ViewModelProvider.Factory 인터페이스를 구현할 수 있습니다.
class ViewModelFactory:ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return if(modelClass.isAssignableFrom(NoParamViewModel::class.java)){
            NoParamViewModel() as T
        } else{
            throw IllegalArgumentException
        }
    }
}

4. 파라미터가 있는 ViewModel - ViewModelProvider.Factory

  • 3번 방법의 연장선에서, 파라미터를 소유하고 있는 ViewModel 객체의 인스턴스를 생성할 수 있습니다. 직접 구현한 Factory 클래스에 파라미터를 넘겨주어 create() 내에서 인스턴스를 생성할 때 활용하면 됩니다.
class HasParamViewModel(val param: String) : ViewModel()
class HasParamViewModelFactory(private val param: String) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return if (modelClass.isAssignableFrom(HasParamViewModel::class.java)) {
            HasParamViewModel(param) as T
        } else {
            throw IllegalArgumentException()
        }
    }
}
class MainActivity : AppCompatActivity() {
 
    private lateinit var hasParamViewModel: HasParamViewModel
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        val sampleParam = "Ready Story"
 
        hasParamViewModel = ViewModelProvider(this, HasParamViewModelFactory(sampleParam))
            .get(HasParamViewModel::class.java)
    }
}

5. 파라미터가 없는 AndroidViewModel - AndroidViewModelFactory

  • 안드로이드 공식 사이트에 의하면 ViewModel 클래스에서 Context 객체를 소유하거나 접근하는 것에 있어서 권장하지 않습니다.(메모리 릭) 하지만 불가피하게 Context를 사용해야할 필요성이 있을 때는 AndroidViewModel 클래스를 사용하면 됩니다.
  • 안드로이드에서는 AndroidViewModel 객체에 대한 생성을 위해 ViewModelProvider.AndroidViewModelFactory라는 별도의 팩토리를 제공합니다.
class NoParamAndroidViewModel(application: Application) : AndroidViewModel(application)
class MainActivity : AppCompatActivity() {
 
    private lateinit var noParamAndroidViewModel: NoParamAndroidViewModel
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        noParamAndroidViewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory(application))
            .get(NoParamAndroidViewModel::class.java)
    }
}

6. 파라미터가 있는 AndroidviewModel

  • 파라미터가 있는 AndroidViewModel 객체를 생성하는 방법입니다.
class HasParamAndroidViewModel(application: Application, val param: String)
    : AndroidViewModel(application)
class HasParamAndroidViewModelFactory(private val application: Application, private val param: String)
    : ViewModelProvider.NewInstanceFactory() {
 
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
            try {
                return modelClass.getConstructor(Application::class.java, String::class.java)
                    .newInstance(application, param)
            } catch (e: NoSuchMethodException) {
                throw RuntimeException("Cannot create an instance of $modelClass", e)
            } catch (e: IllegalAccessException) {
                throw RuntimeException("Cannot create an instance of $modelClass", e)
            } catch (e: InstantiationException) {
                throw RuntimeException("Cannot create an instance of $modelClass", e)
            } catch (e: InvocationTargetException) {
                throw RuntimeException("Cannot create an instance of $modelClass", e)
            }
        }
        return super.create(modelClass)
    }
}
  • ViewModelProvider.Factory 인터페이스를 구현하여도 무방합니다.

-> 해당 글에서는 없지만 android-ktx / fragment-ktx 모듈을 사용하면 보다 편리하게 뷰모델 인스턴스를 생성할 수 도 있습니다.

profile
heec.choi

0개의 댓글