or_dvir
or_dvir

Reputation: 619

Room LiveData observer (onChange) fired multiple times but only for INSERT

I have noticed some strange behavior from the android Room library (at least it looks strange to me).

While there are other posts with similar problems, none of them (that I could find) are quite the same as this.

My issue is that when I observe a LiveData object, my observers' onChange() method is called multiple times but only for INSERT operation. The method will be triggered once for every object I insert (i.e. if I insert a list of N objects, it will be triggered N times), whereas for other operations (such as DELETE) it is fired once no matter the size of the list I am deleting.

I have the following queries in my DAO:

@query("select * from myTable")
LiveData<myEntity> getAll();

@insert
void insert(List<myEntity> entities);

@delete
void delete(List<myEntity> entities);

I am observing the getAll() method and I am definitely calling the delete() and insert() methods one time - something like this:

public void insertAll(List<myEntity> items)
{
    myDao.insert(items);
}

and

public void deleteAll(List<myEntity> items)
{
    myDao.delete(items);
}

Since in my onChange() method I am updating a RecyclerView adapter which is visible to the user, this is a problem as I am getting a lot of duplicates and also I am doing some other things in there which should really only be done once every time the table changes but instead they are executed many times (as I've said, once for every item inserted).

I have read this article and tried to implement tip number 7 but the problem persists. https://medium.com/google-developers/7-pro-tips-for-room-fbadea4bfbd1

Is this by design and considered normal behavior? What can I do to have my observer only fire once for every INSERT operation (even if I insert multiple objects at the same time)?

Upvotes: 1

Views: 2894

Answers (1)

or_dvir
or_dvir

Reputation: 619

while i don't fully understand it, i found the solution!

my problem was that i was calling observe() from onNewIntent() and that my call looks like this:

 mViewModel.getAll().observe(this, new Observer<ArrayList<MyObject>>()...);

the reason i was calling this from onNewIntent() is that this activity can be opened from almost anywhere in my app using the flag BRING_TO_FRONT (or whatever it's called) so onCreate() is not guaranteed to be called so i figured i better make sure that the observer is called by putting it in onNewIntent(). i looked at the docs they say

If the given owner, observer tuple is already in the list, the call is ignored.

so i thought i was safe. what i failed to realize for some reason is that i am in fact creating a new observer every time with the new keyword. that with the combination of calling it from onNewIntent() lead to multiple duplicate observers which caused the onChanged() method to be triggered multiple times (well actually it was only called once, but once per observer!).

once i moved the observe() call to onCreate() the problem was fixed and i get a single call to onChanged() even when i insert multiple items to my table.

however this still does not explain how the delete method was only called once for multiple...

Upvotes: 2

Related Questions