romaneso
romaneso

Reputation: 1122

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

Upvotes: 8

Views: 15354

Answers (5)

adityakamble49
adityakamble49

Reputation: 2011

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

Upvotes: 6

daneejela
daneejela

Reputation: 14233

One more thing - for others with a similar problem - be aware that live data queries will execute only if there is a live observer (i.e. view listening for updates). It won't fill itself just by "laying" there in declarations, like this:

val myLiveData = repository.readSomeLiveData ()

So make sure that you are observing somewhere your LiveData object, either in view or through Transformations.

Upvotes: 0

Vishal Kumar
Vishal Kumar

Reputation: 4627

Livedata is used to observe the data streams. In case you want to call the get a list of your entities stored within the Live Data. Something like this can be helpful.

public class PoliciesTabActivity extends AppCompatActivity {

    private PolicyManualViewModel mViewModel;
    private List<PolicyManual> policyManualList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leaves_tab_manager);

        mViewModel = ViewModelProviders.of(PoliciesTabActivity.this).get(PolicyManualViewModel.class);

        //Show loading screen untill live data onChanged is triggered
        policyManualList = new ArrayList<>();
        mViewModel.getAllPolicies().observe(this, new Observer<List<PolicyManual>>() {
            @Override
            public void onChanged(@Nullable List<PolicyManual> sections) {
                //Here you got the live data as a List of Entities
                policyManualList = sections;
                if (policyManualList != null && policyManualList.size() > 0) {
                     Toast.makeText(PoliciesTabActivity.this, "Total Policy Entity Found : " + policyManualList.size(), Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(PoliciesTabActivity.this, "No Policy Found.", Toast.LENGTH_SHORT).show();
                }
            }
        });

    }
}

Upvotes: 0

Josue B.
Josue B.

Reputation: 11

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.

Upvotes: 1

Martin Ohlin
Martin Ohlin

Reputation: 494

I'm not sure exactly what you are trying to accomplish here, but it is possible to observe without a LifeCycleOwner if you use observeForever instead of observe.

Upvotes: 0

Related Questions