이전에 안드로이드의 구조에 관하여 말하거나 ViewModel이 왜 필요한지에 대하여 말한적은 있지만 정작 ViewModel의 구현에 관하여 말한적은 없는것 같습니다. 이번포스팅에서는 ViewModel을 만들었다면 어떻게 코드에서 사용할수있는지 말해볼까 합니다.
저번에 ViewModel은 Actic가 finish되거나 Fragment가 detach되지 않는이상 살아있어야 한다 말한적이 있습니다.

이렇게 되기위해서는 액티비티나 프래그먼트에서는 ViewModel생성시 ViewModelProvier를 이용하는데 이때 ViewModelStoreOwner를 주게됩니다. 이는 ViewModel을 누가 가지고 있는지 UI-Controller가 누구인지 확인하는 작업에 사용됩니다. 해당 작업에서는 ViewModelStoreOwner에서 가지고 있는 ViewModelStore의 HashMap을 이용해 ViewModel을 찾아서 넘겨줄수 있게됩니다. 이때 ViewModel이 없다면 ViewModelProvier의 Factory class를 이용하여 ViewModel을 생성하게됩니다.
public interface ViewModelStoreOwner {
@NonNull
ViewModelStore getViewModelStore();
}
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
}
이제 구현을 해봅시다
val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
해당방법은 ViewModelProvider를 이용하여 ViewModel을 만드는 방법입니다. MainViewModel::class.java라는 문자열값을 Key값으로 사용해 ViewModel 객체를 가져옵니다. Key에 해당하는 Value가 없으면 생성하고 가져오므로 처음 ViewModel 객체를 만들더라도 get을 통해 가져올 수 있습니다.
이경우 ViewModel에 파라미터가 없다면 이방법이 적절합니다. 만약 ViewModel에 파라미터가 있다면 ViewModelFactory를 사용해서 파라미터를 Factory를 통해 넣어줘야합니다.
//ViewModelProvider.Factory
class MainViewModelFactory(private val searchRepository: SearchRepository) :
ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return MainViewModel(searchRepository) as T
}
}
// 액티비티나 프래그먼트에서
val viewModel = ViewModelProvider(
this,
MainViewModel.MainViewModelFactory(
SearchRepositoryImpl(this)
)
).get(MainViewModel::class.java)
이런식으로 팩토리클래스를 만들어 주입할수있습니다.
안드로이드에는 by lazy라는 변수를 처음 필요로할때 초기화하는 함수가있습니다. Ktx에서는 이러한 lazy를 이용한 viewModels가 있습니다.
private val viewModel: MainViewModel by viewModels()
//뷰모델에 파라미터가 있다면?
private val viewModel: MainViewModel by viewModels{
MainViewModel.MainViewModelFactory(
SearchRepositoryImpl(this)
)
}
이때 ViewModelStoreOwner는 확장함수이므로 따로 넣어주지않아도 호출된곳의 ViewModelStoreOwner가 자동적으로 들어갑니다.
activityViewModels의 경우는 Fragment의 확장함수입니다. 프래그먼트끼리나 액티비티나 프래그먼트끼리 ViewModel을 공유하여 사용하고 싶을때 액티비티에 뷰모델을 만들고 프래그먼트에서 activityViewModels를 이용하여 ViewModel을 공유할수 있습니다.
class FirstFragment : Fragment() {
private val mainViewModel by activityViewModels<MainViewModel>()
}
reference
https://medium.com/@wooongyee/android-viewmodel%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90-%EB%B0%8F-%EC%82%AC%EC%9A%A9%EB%B2%95-c84f3d5d1207
https://velog.io/@jisoo0817/Android-ViewModelProvider%EC%99%80-by-viewModels%EC%97%90-%EB%8C%80%ED%95%B4
https://ranseo.tistory.com/228