androidandroid-livedataandroid-architecture-lifecycleandroid-architecture

Does event wrapper pattern replace the use of SingleLiveEvent?


I'm adopting MVVM to my Android apps recently. In order to solve the problems underlying with the lifecycle of an app, Google had released LiveData.

The usage of LiveData has different scenarios, as pointed out in the medium article wrote by Jose Alcérreca, you can use SingleLiveEvent or something like the event wrapper pattern.

I want to make sure the SingleLiveEvent, or the event wrapper pattern, which one would be the best practice to use with LiveData in Android MVVM architecture. And I found the Google I/O app of this year(2018) have no usages of SingleLiveEvent, it uses event wrapper pattern instead.

Previously I have opened an issue on the project android-architecture, at first I'm seeking an official reply, but it seems to have no comments at all. As a result, I would like to hear the advice from the developers who already use these stuff and have reflections on it.

Please share your precious experiences, thank you in advance.


Solution

  • I'm not a fan of SingleLiveEvent because it restricted to one observer but you can add many observers as well, so it can be error-prone.

    But in a very simple scenario(like the todo app that you mentioned), it can be a better option than event wrapper pattern.

    In a complex scenario, event wrapper pattern would be a better option, but it also has some limitations. This implementation assumes you only have one main consumer (see getContentIfNotHandled). So, I think dealing with multiple observers will cause boilerplate to decide which one is the main consumer or when I should call getContentIfNotHandled or peekContent.

    But, All these limitations can be fixed with your own implementation.

    For example here is an extended version of SingleLiveEvent that supports multiple observers:

    public class SingleLiveEvent<T> extends MutableLiveData<T> {
    private LiveData<T> liveDataToObserve;
    private final AtomicBoolean mPending = new AtomicBoolean(false);
    
    public SingleLiveEvent() {
        final MediatorLiveData<T> outputLiveData = new MediatorLiveData<>();
        outputLiveData.addSource(this, currentValue -> {
            outputLiveData.setValue(currentValue);
            mPending.set(false);
        });
        liveDataToObserve = outputLiveData;
    }
    
        @MainThread
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
            liveDataToObserve.observe(owner, t -> {
                if(mPending.get()) {
                    observer.onChanged(t);
                }
            });
        }
    
        @MainThread
        public void setValue(T value) {
            mPending.set(true);
            super.setValue(value);
        }
    }
    

    As you see, It's not about SingleLiveEvent vs event wrapper pattern, It all depends. Personally, I use other patterns (like patterns existing in React/Flux world) for dealing with states.

    Keep in mind that there is no silver bullet in software engineering.