이 글은 기존 운영했던 WordPress 블로그인 PyxisPub: Development Life (pyxispub.uzuki.live) 에서 가져온 글 입니다. 모든 글을 가져오지는 않으며, 작성 시점과 현재 시점에는 차이가 많이 존재합니다.
작성 시점: 2018-04-01
Android Architecture Components 의 도입 이후, 안드로이드 앱에 MVVM 구조를 도입하는 자체가 쉬워졌다.
ViewModel 페이지를 보면 ViewModel 클래스를 상속하여 ViewModelProviders 로 통해 가져오게 하는 걸 볼 수 있는데, 주로 조건에 따라 뷰를 숨기고 표시하기 위해 간단히만 소개하자면..
이렇게 될 것이다.
그런데, 언젠가는 mSelectedMode 는 누군가에 의해서 (사용자의 UI 반응이든, Data Source의 반응이든) 변경되는데, 이 때 아무리 값을 바뀌어도 visibility 는 변경되지 않는다.
이를 해결하기 위해서 DataBinding 에는 Observable 란 개념이 있고, 여기에서는 mSelectedMode 자체를 ObservableField (또는 ObservableBoolean) 를 선언하면 된다.
하지만, 그렇게 쉽게 해결되지는 않는다. 실제로 실행시켜보면 BaseObservable 라는 객체를 상속시켜야 된다는 Exception 이 발생한다.
하지만 이미 우리는 ViewModel 라는 객체를 상속중이어서, 직접 BaseObservable 내용을 구현시켜줘야 한다.
여기서는 그 방법을 살펴볼 것이다.
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 작업) 을 쉽게 할 수 있게 된다.