[수정] ViewModel의 ViewModelProvider
MVVM구조를 기반을 사용하려 했고 Main에서 두 개의 fragment에 하나의 ViewModel(이하 vm)을 참조하고 싶었다.
간단한 vm예제들은 하나의 fragment or activity(view) 내에서는 provider를 통해 vm을 주입을 시키지만 해당 view가 다수일 때 하나의 vm을 어떻게 처리할 것인지의 의문이 생겼다.
통상 MVVM은 vm이 1:N, N:1의 구조를 가진다.
ViewModelProviders는 deprecate된다!(너무 늦게 인지를 해버렸다ㅜ)
2020년 03월 31일 기준,
구 버전 - implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
최신 버전 - implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
이하 내내용의 수정이 필요하다.
ViewModelProviders.of의 매서드가, ViewModelProvider class로 들어갔고 사용방법은 유사하다.
사용방법은 유사하나 내부 코드를 보면 기존보다 더욱 깔끔해졌다.
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
기존엔 activity, fragment를 파라미터로 받았지만, 이제는 ViewModelStoreOwner를 파마미터로 받는다.
결론.
서두에서 이야기한, 즉 하나의 화면에 여러 개의 fragment를 사용할 때 동일한 viewmodel을 참조하고 싶다면
화면의 fragment, activity의 ViewModelStoreOwner를 호출하면 된다.
ViewModelProvider(activity.viewModelStore).get(MainViewModel::class.java)
.viewModelStore로 불러왔지만 생략 가능하다.
중간에 Factory라는 클래스가 나왔다.
그럼 이 클래스의 역할이 무엇일까?
Factory는 vm클래스를 생성할 때 vm에 초기 파라미터를 전달할 때 사용한다. (초기 데이터가 필요 없을 경우 생략해도 된다.)
class MainViewModelFactory<T>(var userId: Int) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
return MainViewModel(userId) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
위 코드와 유사하게 원하는 파라미터 값을 전달하여 viewmodel에 저장하게 한다. (userId로 1을 넣었다.)
아래는 호출 방법이다.
ViewModelProvider(activity, MainViewModelFactory<MainViewModel>(1)).get(MainViewModel::class.java)
이하 내용은 참조로만 봐주시면 감사하겠습니다.
----------------------------------------------------------------------------------------------------------------------------
ViewModelProviders Class 내부로 들어가면 of메서드가 여러개 오버라이딩되어 있다.
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment) {
return of(fragment, null);
}
해당 매서드 내부에는 of매서드를 통해 Factory를 파라미터로 받는다.
(해당 코드는 fragment를 파라미터로 받았지만, Fragment | FragmentActivity 가능하다.)
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
Application application = checkApplication(checkActivity(fragment));
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(fragment.getViewModelStore(), factory);
}
마지막 코드의 ViewModelProvider를 인스턴스 진행과정에서 fragemnt.getViewModelStrore()를 통해 해당 fragment/activity의 getViewModelStore() 메서드를 통해 해당 viewmodel를 저장하거나 불러온다.
@NonNull
@Override
public ViewModelStore getViewModelStore() {
if (getContext() == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
return mViewModelStore;
}
----------------------------------------------------------------------------------------------------------------------------
참조링크
https://thdev.tech/androiddev/2018/08/05/Android-Architecture-Components-ViewModel-Inject/