Databinding - ObservableField with MVVM

WindSekirun (wind.seo)·2022년 4월 26일
0

이 글은 기존 운영했던 WordPress 블로그인 PyxisPub: Development Life (pyxispub.uzuki.live) 에서 가져온 글 입니다. 모든 글을 가져오지는 않으며, 작성 시점과 현재 시점에는 차이가 많이 존재합니다.

작성 시점: 2018-04-01

Android Architecture Components 의 도입 이후, 안드로이드 앱에 MVVM 구조를 도입하는 자체가 쉬워졌다.

ViewModel 페이지를 보면 ViewModel 클래스를 상속하여 ViewModelProviders 로 통해 가져오게 하는 걸 볼 수 있는데, 주로 조건에 따라 뷰를 숨기고 표시하기 위해 간단히만 소개하자면..

  • XML 의 variable 선언 공간에 해당 ViewModel 를 선언
  • XML 에서 android:visibility="@{viewModel.mSelectedMode ? View.GONE : View.VISIBLE}" 조건문을 사용
  • Activity/Fragment 에서 DataBinding 객체를 불러올 때 ViewModel 설정

이렇게 될 것이다.

그런데, 언젠가는 mSelectedMode 는 누군가에 의해서 (사용자의 UI 반응이든, Data Source의 반응이든) 변경되는데, 이 때 아무리 값을 바뀌어도 visibility 는 변경되지 않는다.

이를 해결하기 위해서 DataBinding 에는 Observable 란 개념이 있고, 여기에서는 mSelectedMode 자체를 ObservableField (또는 ObservableBoolean) 를 선언하면 된다.

하지만, 그렇게 쉽게 해결되지는 않는다. 실제로 실행시켜보면 BaseObservable 라는 객체를 상속시켜야 된다는 Exception 이 발생한다.

하지만 이미 우리는 ViewModel 라는 객체를 상속중이어서, 직접 BaseObservable 내용을 구현시켜줘야 한다.

여기서는 그 방법을 살펴볼 것이다.

BaseViewModel 구현

BaseObservable 구현체는 약 5~60줄 정도 되기에, 모든 ViewModel 에 넣기에는 적합하지 않다. 따라서 BaseViewModel 란 객체를 만들고, 그 곳에서 구현할 것이다.

BaseViewModel 자체는 ViewModel 객체 (정확히는 ApplicationContext 사용을 위해 AndroidViewModel 를 사용할 것이다) 를 상속하고, Observable 와 LifecycleObserver 를 구현시킬 것이다.

public abstract class BaseViewModel extends AndroidViewModel implements LifecycleObserver, Observable {

    private PropertyChangeRegistry mCallbacks;

    public BaseViewModel(@NonNull Application application) {
        super(application);
    }

    @Override
    public void addOnPropertyChangedCallback(OnPropertyChangedCallback onPropertyChangedCallback) {
        if (mCallbacks == null) {
            mCallbacks = new PropertyChangeRegistry();
        }

        mCallbacks.add(onPropertyChangedCallback);
    }

    @Override
    public void removeOnPropertyChangedCallback(OnPropertyChangedCallback onPropertyChangedCallback) {
        if (mCallbacks == null) {
            mCallbacks = new PropertyChangeRegistry();
        }

        mCallbacks.remove(onPropertyChangedCallback);
    }
}

그리고 추가적으로 PropertyChangeRegistry 에 등록한 객체가 변경되었음을 알려주는 메서드를 추가적으로 구현한다.

public void notifyChange() {
    synchronized (this) {
        if (mCallbacks == null) {
            return;
        }
    }
    mCallbacks.notifyCallbacks(this, 0, null);
}

public void notifyPropertyChanged(int fieldId) {
    synchronized (this) {
        if (mCallbacks == null) {
            return;
        }
    }
    mCallbacks.notifyCallbacks(this, fieldId, null);
}

사용

@InjectViewModel
public class SignupViewModel extends BaseViewModel {
    public ObservableField<Boolean> mSelectedMode = new ObservableField<>(false); 

    @Inject
    public SignupViewModel(@NonNull Application application) {
        super(application);
    }

    public void setSelectedMode(boolean selectedMode) {
        mSelectedMode.set(selectedMode);
    }
}

이제 어딘가에서 setSelectedMode 메서드를 호출해 값을 변경하거나, mSelectedMode 자체를 변화시키면 그에 따라 UI도 자동으로 변경된다.

이를 이용해서 일정 조건일 때 뷰를 숨기고 - 보이고 등의 작업 (예를 들어 No Data available 작업) 을 쉽게 할 수 있게 된다.

profile
Android Developer @kakaobank

0개의 댓글