Android(+ Kotlin)

[수정] ViewModel의 ViewModelProvider

Charko 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/

http://dalinaum.github.io/android/2018/07/20/viewmodel.html