이 포스팅에서 Dagger2ViewModel에 대한 설명은 다루지 않습니다.

Dagger2와 AAC의 ViewModel같이 썼을때의 문제점

Dagger2와 ViewModel을 같이 쓰다가 생긴 문제가 하나 있습니다.

AAC뷰모델을 쓴다면, 액티비티의 configurationChange가 발생했을때 ViewModel의 인스턴스를 새로 만들지 않고 유지하는게 장점중 하나인데, Dagger2를 통해 ViewModel인스턴스를 인젝션했을 때 매번 새로운 인스턴스를 만들어낸다는 것입니다.

원인은 appcompat Support Library에 있었습니다.

Activity의 인스턴스가 새로 생성되더라도 ViewModel 인스턴스가 그대로 유지될수 있는 이유가 ViewModelProviders를 통해 싱글톤 형태로 저장하고 있기 때문입니다.

public class HolderFragment extends Fragment implements ViewModelStoreOwner {
    ...
    
    private ViewModelStore mViewModelStore = new ViewModelStore();
   
    ...
   
    public HolderFragment() {
        setRetainInstance(true);
    }

    ...
}

위 코드를 보시면 HolderFragment라는 프레그먼트는 ViewModelStoreOwner를 구현하고, ViewModelStore라는 뷰모델 저장소를 들고 있습니다.  setRetainInstance(true)가 생성자 단에서 호출되어있기 때문에 프레그먼트가 이전상태를 기억하므로, 액티비티가 재생성되도 이 프레그먼트가 복구 되면서 이전 뷰모델을 가져올수 있었던 것입니다.

Dagger2 사용시 일반적으로 Inject()하는 시점은 액티비티의 super.onCreate() 이전입니다.

onCreate()가 불리는 시점 이전이라면 프레그먼트가 복구가 아직 안된 상태이기때문에 ViewModel을 찾으려고 해도 찾을수가 없게되어 새로 생성하게 되었던 것입니다.

appcompat support library 28버전 이후로는 ViewModelStoreOwner를 FragmentActivity에 구현을 했기때문에

@NonNull
public ViewModelStore getViewModelStore() {
    if (this.getApplication() == null) {
        throw new IllegalStateException("Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call.");
    } else {
        if (this.mViewModelStore == null) {
            FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
            if (nc != null) {
                this.mViewModelStore = nc.viewModelStore;
            }
            if (this.mViewModelStore == null) {
                this.mViewModelStore = new ViewModelStore();
            }
        }
        return this.mViewModelStore;
    }
}

다음과 같이 이전 상태가 이미 복구된 상태로 ViewModelStore를 가져올 수 있습니다.

실제 mLastNonConfigurationInstances가 assign되는 단계는 Activity내의 attach()인데 internalAPI라 보이진 않습니다.

Conclusion

ViewModel을 Dagger에서 사용시에는 Appcompat Support Library가 28이상인지 꼭 확인해야 합니다.

카테고리: 미분류

0개의 댓글

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.