LiveData onChanged not being called when data changes

livedata observer not called
android-livedata observer called multiple times
convert livedata to mutablelivedata
singleliveevent android
livedata post value not working
android-livedata called twice
livedata observe once
mutable live data vs live data

I am new to using LiveData and ViewModels and I don't fully understand how the data is updated.

According to the Android Dev site:

Instead of updating the UI every time the app data changes, your observer can update the UI every time there's a change.

That sentence doesn't make sense to me. I'm using a Sqlite database (without Room) and I'm asynchronously getting the data in the getItems() method of the ViewModel. Does that mean when data is added or updated in the database, the LiveData will automatically detect it and onChange is called?

According to the Android dev site, it says to begin observing a LiveData object in onCreate. Before using LiveData, I was refreshing the data in onResume by querying the database then calling notifyDataSetChanged().

This code I have now displays the data when the Fragment loads, but if I delete or add new data to the database, the UI does not reflect the change. I just think I don't have a basic understanding of how LiveData works and I can't find a good explanation anywhere.

Help me StackOverflow, you're my only hope.

public class MyViewModel extends AndroidViewModel {
    private MutableLiveData<List<String>> items;
    private Application application;

    public MyViewModel(@NonNull Application application) {
        super(application);
        this.application = application;
    }

    public MutableLiveData<List<String>> getItems() {
        if (items == null) {
            items = new MutableLiveData<>();
            getItems();
        }
        return items;
    }

    private void getItems() {
        List<String> items = GetItems(); //async process

        this.items.setValue(items)
    }
}

public class ListFragment extends Fragment {

    @Override
    public void onCreate(final Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        MyViewModel model = ViewModelProviders.of(getActivity()).get(MyViewModel.class);

        final Observer<List<String>> observer = new Observer<List<String>>() {
            @Override
            public void onChanged(List<String> items) {
                //update UI
            }
        };

        model.getItems().observe(this, observer);
    }

}

You're retrieving items only once if private MutableLiveData<List<String>> items hasn't been initialised yet:

public MutableLiveData<List<String>> getItems() {
    if (items == null) {
        items = new MutableLiveData<>();
        getItems();// it's called only once 
    }
    return items;
}

One way to overcome this issue could be to use ContentObserver for your data:

...
private final ContentObserver contentObserver = new ContentObserver(new Handler()) {
    @Override
    public void onChange(boolean selfChange) {
        // if there're any changes then perform the request and update the UI
        getItems(); 
    }
};
...

Don't forget to register it to get notified of changes in the DB:

...
contentResolver.registerContentObserver(<your data content uri>, true, contentObserver);
...

I would also suggest to create a separate Repository layer responsible for data retrieval that could look as follows:

...
private final ContentObserver contentObserver = new ContentObserver(new Handler()) {
    @Override
    public void onChange(boolean selfChange) {
        // if there're any changes then perform the request and update the UI
        getItems(); 
    }
};

public LiveData<List<String>> getItems() {
    return new MutableLiveData<String>() {
        @Override
        public void onActive() {
           // your async operation here
           new Thread({
               List<String> items = db.getItems();
               postValue(items);
           }).start();

           contentResolver.registerContentObserver(<your data content uri>, true, contentObserver); 
        }

        @Override
        public void onInactive() {
            contentResolver.unregisterContentObserver(contentObserver); 
        }
    }
    return liveData;
}   
... 

Then, your ViewModel would need to inject the repository object and hence would require ViewModelFactory to build an instance of your ViewModel but the overall usage would look similar to this:

public class MyViewModel extends AndroidViewModel {   
    ... 
    public MutableLiveData<List<String>> getItems() {
        dataRepository.getItems();
    }
    ...
}

To get more information please read Guide to app architecture

LiveData Overview, MediatorLiveData onChanged not getting called - android. In my app I am trying to use MediatorLiveData to listen to the changes to a livedata. setValue( Resource.loading(null)); //TODO:: Add method to check if data should be saved. When the observed data changes while the activity is in the foreground, the onChanged() method is invoked and updates the data cached in the adapter. Note that in this case, when the app opens, the initial data is added, so onChanged() method is called.

Your code seems correct. You are setting up everything correctly and you will get a callback on your Observer in the ListFragment each time the LiveData value changes.

However, with that code, the LiveData value will never change, hence your LiveData's Observer will get called only once. You are calling MyViewModel.getItems only once, in the onCreate and this method will do two things: return the LiveData AND fetch the item list.

A first approach for you would be to divide your ViewModel getItems method into two: one for getting the LiveData and one for refreshing the actual list of items. In the Fragment, you would then refresh your data in the onResume(), as you used to.

It would look something like this:

public class MyViewModel extends ViewModel {
    private final MutableLiveData<List<String>> items = new MutableLiveData<>();

    public LiveData<List<String>> getItemsLiveData() {
        return items;
    }

    public void refreshItems() {
        List<String> items = GetItems(); //async process

        this.items.setValue(items)
    }
}

public class ListFragment extends Fragment {

    private MyViewModel model;

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        model = ViewModelProviders.of(getActivity()).get(MyViewModel.class);

        final Observer<List<String>> observer = new Observer<List<String>>() {
            @Override
            public void onChanged(List<String> items) {
                //update UI
            }
        };

        model.getItemsLiveData().observe(this, observer);
    }

    @Override
    public void onResume() {
        model.refreshItems()
    }
}

To go further, you will need to change the way you actually refresh items. If you want to be notified in your ViewModel when the database is modified, you will also need to use an Observer pattern in the communication between ViewModel and Database (Room with LiveData, RxJava's Observable or the new coroutine Flow are good places to start)

Here is a pseudo-algorithm example using RxJava (but that's up to you to choose which Observer library to use):

public class MyViewModel extends ViewModel {
    private final MutableLiveData<List<String>> items = new MutableLiveData<>();

    public MyViewModel() {
        // In actual code, don't forget to dispose that subscription in ViewModel.onCleared()
        myDatabase.getDatabaseObservable()
            .subscribe(new Subscriber<List<String>>() {
                @Override
                public void onCompleted() {
                }

                @Override
                public void onNext(List<String> newItems) {
                    items.setValue(newItems)
                }

                @Override
                public void onError() {
                }
            })
    }

    public LiveData<List<String>> getItemsLiveData() {
        return items;
    }
}

The last part in there would be to create that Observable in your Database class (either with a Library that does it automatically like Room or by creating your own PublishSubject).

MediatorLiveData onChanged not getting called, LiveData observer's onChanged gets called on activity rotation even though there was no change in the data - android. Note: Make sure to store LiveData objects that update the UI in ViewModel objects, as opposed to an activity or fragment. You see our UI controllers are only responsible to store data not for holding data state. By UI controllers mean our ViewModel and LiveData class. What is MutableLiveData: MutableLiveData is also a LiveData.

Your code seems to be set up correctly. But your Observers's onChanged() method will be called once since there is no part of your code notifying it of the change you are making to the underlying data.

I would suggest you explicitly notify your observer of changes in the data by using the MutableLiveData's setValue() or postValue() method depending on whether they are called from the main thread or background thread respectively. Or better still implement ROOM database with its Data Access Object (DAO) objects.

Here is a code snippet of where I did something similar if you are not willing to use ROOM just yet:

class HomeViewModel : ViewModel() {

private val _budgetList = MutableLiveData<ArrayList<Budget>>()
val budgetList: LiveData<ArrayList<Budget>> = _budgetList

private val _billList = MutableLiveData<ArrayList<Bill>>()
val billList: LiveData<ArrayList<Bill>> = _billList

init {
    _budgetList.value = getBudgetList()
    _billList.value = getBills()
}

fun deleteBudget(pos: Int) {
    _budgetList.apply {
        val newValue = value?.apply { removeAt(pos) }  header position
        postValue(newValue)
    }
}

}

After removing a value from the list, the new list is sent to the Livedata for an update via the postValue() method. Simply removing this value without posting it will not trigger the onchange() method of the Livedata's Observer. I hope this help someone.

LiveData observer's onChanged gets called on activity rotation even , Normally, the UI elements are notified when there is a change in data. increased and also the color of the like button will be changed to red from white. out with the help of ViewModel and to make the working of a ViewModel easy, For example, if you are not using LiveData and you are updating some� This test fails because LiveData doesn’t do more work than needed. Reading liveData2.valuedoesn’t initiate the chain of dependent transformations because it’s not observed. Only a

Understanding LiveData in Android, Sign up and get an extra one for free. Android: How to Fix a Serious Problem in LiveData. Avoid observing the same data whenever component life-cycle changes If it's not, it might hold the data and deliver it when that specific component comes When new data is posted, the onChanged function is triggered and the flag� LiveData subclass which may observe other LiveData objects and react on OnChanged events from them. LiveData is a data holder class that can be observed within a given lifecycle. This means that an Observer can be added in a pair with a LifecycleOwner , and this observer will be notified about modifications of the wrapped data only if the

Android: How to Fix a Serious Problem in LiveData, From its explanation, it is a subclass of liveData which can 'observe' other From the sample code above, when source's value is changed, the LiveData data class ResponseError(val code: Int? = null, val Tips: OnChanged() method will not be called if MediatorLiveData is Get our stories delivered. Once the repository changes the FollowStatus value stored in its LiveData instance, the activity’s onChanged code gets called again, as the activity observes the FollowStatus and waits for changes in the data. This is how the data-change <-> UI change cycle works with LiveData. The new thing about LiveData is that it’s lifecycle-aware.

LiveData to the next level with MediatorLiveData and , Unlike the typical observables, a LiveData observable is, wait for it… No more Lifecycle handling: UI components just observe relevant data and don't stop or Create an Observer object that defines the onChanged() method, which controls what happens when the LiveData object's held data changes. I am having an issue where data that is written to my Room database does not appear in a ViewModel even though I am writing it synchronously. This is what a log would look like: com.widget D/WriteActivity: Writing widget data to the database com.widget D/WriteActivity: Starting the ReadActivity com

Comments
  • The problem is that you're only getting the items once, in your getItems() method. For it to work as you're expecting, you'll need to use a Room DAO and observe the DAO in the ViewModel. When the DAO observer in the ViewModel detects changes to the underlying data, then update the LiveData, and then the Fragment will get the updated data.
  • I see. So if I'm not using Room does it makes sense to even use LiveData?
  • Are you able to call again private void getItems() function once you have deleted or added elements to your database? If yes, call it again.
  • Can I just make getItems() public?
  • I had the same problem as the OP, but my issue was that my Fragment was not obtaining the same instance of the ViewModel that my Activity was. More here: stackoverflow.com/questions/61373456/… .