Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LiveData Object keeps being null after getValue() is called

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

like image 906
romaneso Avatar asked Dec 29 '17 15:12

romaneso


People also ask

In which method should you observe a LiveData object?

Observe LiveData objects In most cases, an app component's onCreate() method is the right place to begin observing a LiveData object for the following reasons: To ensure the system doesn't make redundant calls from an activity or fragment's onResume() method.

Why is LiveData null?

getValue() , while livedata are used to observe the data. May be when you are checking in next line, data is not set in livedata that's why it gives you null. In short if you don't want to use LiveData then just use it without LiveData .

What is LiveData and MutableLiveData?

MutableLiveData is commonly used since it provides the postValue() , setValue() methods publicly, something that LiveData class doesn't provide. LiveData/MutableLiveData is commonly used in updating data in a RecyclerView from a collection type(List, ArrayList etc).

What is mediator live data android?

MediatorLiveData is a subclass of MutableLiveData that can observe other LiveData objects and react to OnChanged events from them.


2 Answers

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

like image 167
adityakamble49 Avatar answered Sep 20 '22 21:09

adityakamble49


In order for the LiveData object works well you need to use the observe method. That is if you want to use the getValue() method and expecting a non-null response you need to use the observe method. Make sure initialize the LiveData object in your ViewModel as @adityakamble49 said in his answer. For initialize the object, you can pass the reference of your LiveData object which was created in your Repository:

ViewModel.java

private LiveData<Client> clientLiveData;
private ClientRepository clientRepo;
public ViewModel(ClientRepository clientRepo) {
    this.clientRepo = clientRepo;
    clientLiveData = clientRepo.getData();
}

Then you have to observe your ViewModel from the Activity and call the method that you want to update in your ViewModel (or Repo, but remember that Repo conects with the ViewModel and ViewModel with the UI: https://developer.android.com/jetpack/docs/guide ):

Activity.java

viewModel.getClient().observe(this, new Observer<Client>() {
        @Override
        public void onChanged(@Nullable Client client) {
            viewModel.methodWantedInViewModel(client);
        }
    });

I hope it helps.

like image 33
Josue B. Avatar answered Sep 22 '22 21:09

Josue B.