LiveData Object keeps being null after getValue() is called

不羁的心 提交于 2020-04-10 09:16:20

问题


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


回答1:


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




回答2:


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.




回答3:


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.




回答4:


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();
                }
            }
        });

    }
}



回答5:


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.



来源:https://stackoverflow.com/questions/48025008/livedata-object-keeps-being-null-after-getvalue-is-called

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!