LiveData two-way databinding WITHOUT exposing MutableLiveData

We have been recommended to switch from ObservableField to LiveData for data binding because it is lifecycle-aware. We have also been recommended not expose MutableLiveData because the view model should control assignment.

This works perfectly for one-way data binding and in those cases I would only expose LiveData.

We want to use two-way data binding, which by definition moves assignment from the view model to the UI, so I think in this case exposing MutableLiveData is correct. I say this as we are doing it on purpose because we want our UI to be able to assign values so that we have cleaner views.


I've forgotten about this issue for a while, but as a workaround I've extended MutableLiveData slightly and use this instead every time I need control over the setter.

import androidx.core.util.Consumer;
import androidx.lifecycle.MutableLiveData;

public class DelegatedMutableLiveData<T> extends MutableLiveData<T> {
    private Delegate<T> mDelegate;

    public interface Delegate<T> {
        void onSet(T value, Consumer<T> setter);
    }

    public DelegatedMutableLiveData(Delegate<T> delegate) {
        mDelegate = delegate;
    }

    public DelegatedMutableLiveData(T value, Delegate<T> delegate) {
        super(value);
        mDelegate = delegate;
    }

    @Override
    public void setValue(T value) {
        if (mDelegate != null) {
            mDelegate.onSet(value, super::setValue);
        } else {
            super.setValue(value);
        }
    }
}

now use DelegatedMutableLiveData as follows:

private final DelegatedMutableLiveData<Integer> mMyLiveData = new DelegatedMutableLiveData<>((value, setter) -> {
    // do your checks and change value if necessary
    setter.accept(value); // or don't accept if you don't want to change the current value
});