LiveData Object keeps being null after getValue() is called

romaneso picture romaneso · Dec 29, 2017 · Viewed 12.1k times · Source

I want to update a member variable of an object inside my Repository on a LiveData- Object. The problem is, that if I call the getValue() Method, I keep getting an NullPointerException, although the value does exist inside my Room- Library.

My question now is, how do I get the value from the LiveData Object without calling the observe() Method? (I am not able to call the observe method inside my repository, cause that method wants me to enter a LifeCycleOwner- reference, which is not present inside my repository).

Is there any way to get the value out of the LiveData- object?

My architecture looks like that: ViewModel --> Repository --> Dao

Answer

adityakamble49 picture adityakamble49 · Jan 5, 2018

You need to initialize LiveData object in ViewModel before observing it in Activity/Fragment like this

ProductViewModel.java

public ProductViewModel(DataRepository repository, int productId) {
    mObservableProduct = repository.loadProduct(mProductId);
}
public LiveData<ProductEntity> getObservableProduct() {
    return mObservableProduct;
}

Here observableProduct is LiveData for observing product details which is initialized in constructor and fetched using getObservableProduct() method

Then you can observe the LiveData in Activity/Fragment like this

MainActivity.java

productViewModel.getObservableProduct().observe(this, new Observer<ProductEntity>() {
    @Override
    public void onChanged(@Nullable ProductEntity productEntity) {
        mProduct = productEntity;
    }
});

As you already setup your code architecture like Flow of LiveData is

DAO -> Repository -> ViewModel -> Fragment

You don't need to observe LiveData in repository because you cannot update UI from there. Observe it from Activity instead and update UI from there.

As you are saying its giving null on getValue(), make sure you are updating db and fetching db from single instance of DAO as per I worked with DAO it will not notify db update of one DAO instance to 2nd DAO instance with LiveData

Also you can observeForever as suggested by @Martin Ohlin, but it will not be lifecycle aware and may lead to crashes. Check your requirement before observing forever

Refer to this for Full LiveData Flow

Refer to this for DAO issues

Edit 1 - Without using LifecycleOwner

You can use void observeForever (Observer<T> observer) (reference) method to observe LiveData without providing any LifecycleOwner as I provided by using this context in above example.

This is how you can observe LiveData without providing any LifecycleOwner and observe the LiveData in repository itself

private void observeForeverProducts() {
    mDatabase.productDao().loadAllProducts().observeForever(new Observer<List<ProductEntity>>() {
        @Override
        public void onChanged(@Nullable List<ProductEntity> productEntities) {
                Log.d(TAG, "onChanged: " + productEntities);
            }
        });
    }

But you need to call removeObserver(Observer) explicitly to stop observing the LiveData which was automatically done in previous case with LifecycleOwner. So as per documentation

You should manually call removeObserver(Observer) to stop observing this LiveData. While LiveData has one of such observers, it will be considered as active.

As this doesn't require LifecycleOwner you can call this in Repository without using this parameter as you mentioned which is missing in your repository