ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [수정] ViewModel의 ViewModelProvider
    Android(+ 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/

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

    댓글

Designed by Tistory.