Is it possible to enforce non-nullability of LiveData values?

A new option is available if you use Kotlin. You can replace LiveData with StateFlow. It is more suitable for Kotlin code and provides built-in null safety.

Instead of using:

class MyViewModel {
    val data: LiveData<String> = MutableLiveData(null) // the compiler will allow null here!
}

class MyFragment: Fragment() {
    model.data.observe(viewLifecycleOwner) {
        // ...
    }
}

You can use:

class MyViewModel {
    val data: StateFlow<String> = MutableStateFlow(null) // compilation error!
}

class MyFragment: Fragment() {
    lifecycleScope.launch {
        model.data.collect {
          // ...
        }
    }
}

StateFlow is part of coroutines and to use the lifecycleScope you need to add the lifecycle-extensions dependency:

implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"

Note that this API has been experimental before coroutines 1.4.0.

Here's some additional reading about replacing LiveData with StateFlow.

As Igor Bubelov pointed out, another advantage of this approach is that it's not Android specific so it can be used in shared code in multiplatform projects.


It's possible to do it safely only if you are in control of the code which sets the data because you'll also have to wrap the LiveData class. This way the data setting methods will be protected with @NonNull and you can be sure that the data has already been checked before reaching the Observer.

Wrap the LiveData class:

public class NonNullMutableLiveData<T> extends MutableLiveData<T> implements NonNullLiveData<T> {

    private final @NonNull T initialValue;

    public NonNullMutableLiveData(@NonNull T initialValue) {
        this.initialValue = initialValue;
    }

    @Override
    public void postValue(@NonNull T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(@NonNull T value) {
        super.setValue(value);
    }

    @NonNull
    @Override
    public T getValue() {
        //the only way value can be null is if the value hasn't been set yet.
        //for the other cases the set and post methods perform nullability checks.
        T value = super.getValue();
        return value != null ? value : initialValue;
    }

    //convenience method
    //call this method if T is a collection and you modify it's content
    public void notifyContentChanged() {
        postValue(getValue());
    }

    public void observe(@NonNull LifecycleOwner owner, @NonNull NonNullObserver<T> observer) {
        super.observe(owner, observer.getObserver());
    }
}

Create an interface for exposing as immutable:

public interface NonNullLiveData<T> {

    @NonNull T getValue();

    void observe(@NonNull LifecycleOwner owner, @NonNull NonNullObserver<T> observer);
}

Finally, wrap the Observer:

//not implementing Observer<T> to make sure this class isn't passed to
//any class other than NonNullMutableLiveData.
public abstract class NonNullObserver<T> {

    public Observer<T> getObserver() {
        return new ActualObserver();
    }

    public abstract void onValueChanged(@NonNull T t);

    private class ActualObserver implements Observer<T> {

        @Override
        public void onChanged(@Nullable T t) {
            //only called through NonNullMutableLiveData so nullability check has already been performed.
            //noinspection ConstantConditions
            onValueChanged(t);
        }
    }
}

Now you can create your data like this:

class DataSource {
    private NonNullMutableLiveData<Integer> data = new NonNullMutableLiveData<>(0);

    public NonNullLiveData<Integer> getData() {
        return data;
    }
}

And use it like this:

dataSource.getData().observe(this, new NonNullObserver<Integer>() {
            @Override
            public void onValueChanged(@NonNull Integer integer) {

            }
        });

Completely null safe.


If you use Kotlin, you can create much nicer non-null observe function with extension. There is an article about it. https://medium.com/@henrytao/nonnull-livedata-with-kotlin-extension-26963ffd0333