-
[수정] ViewModel의 ViewModelProviderAndroid(+ Kotlin) 2019. 12. 30. 15:27
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/
'Android(+ Kotlin)' 카테고리의 다른 글
코루틴(Coroutine) - 기본개념 (2) 2020.01.16 MVVM 따라하기 Data Binding + LiveData(2) (0) 2020.01.09 MVVM 따라하기 Data Binding, LiveData (1) (0) 2019.12.20 [Kotlin]무작정 따라하기3 (0) 2019.11.11 [Kotlin]무작정 따라하기2 (0) 2019.11.08