Tom11
Tom11

Reputation: 2519

MutableLiveData does not notify observer

I am trying to use MutableLiveData with pre-filled value from database, but Observer always returns null as book. I need to keep it as MutableLiveData, NOT LiveData, because I have to set it programatically on some places. Therefore I am calling setValue with LiveData retrieved from DB. Code:

ViewModel:

private final MutableLiveData<Book> bookLiveData;

public MyViewModel(@NonNull Application application) {
    super(application);
    ...
    book = new MutableLiveData<>();
    bookLiveData.setValue(bookRep.getBookLiveData().getValue());
    ....
}

Fragment:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    ...
    getActivity().getBookLiveData().observe(getViewLifecycleOwner(), book -> {
            ... // When fragment is created, book is always null here
    });
}

Can somebody tell me why is Book null in observer? I thought that Observer would be notified when bookRep.getBookLiveData() is finished and value is retrieved. THank you for your help.

Upvotes: 1

Views: 2946

Answers (1)

Sanlok Lee
Sanlok Lee

Reputation: 3494

bookRep.getBookLiveData().getValue() will always return null. Since you are setting a null value in the ViewModel like this: bookLiveData.setValue(null) at line 7, bookLiveData is always null at initial launch.

You cannot use getValue() on a LiveData object to get value here because it is always null at initialization. You need to observe so that you get notified when it actually emits a value.

There are several different ways to solve it. One way is to observe getBookLiveData() in the ViewModel using observeForever() method.

private LiveData<Book> bookFromRep;
private MutableLiveData<Book> bookLiveData = new MutableLiveData<>();
private Observer<Book> bookObserver = bookLiveData::postValue; // Book observer posts value to bookLiveData.

public MyViewModel(@NonNull Application application) {
    super(application);
    ...
    bookFromRep = bookRep.getBookLiveData();
    bookFromRep.observeForever(bookObserver);
    ....
}

@Override
protected void onCleared() {
    super.onCleared();

    // Don't forget to remove observer when you use observeForever()
    bookFromRep.removeObserver(bookObserver);
}

Another, and arguably a better, approach to this problem is to use MediatorLiveData. I won't include its implementation here but what I recommend is to understand different approaches and find the best approach that fits your need.

Upvotes: 2

Related Questions