Search code examples
javaandroidandroid-livedatamutablelivedata

Why is onChanged not called when value changed in LiveData List?


Context

Using MutableLiveData<List<Integer>> to hold a values. When the first value (using first value as example for brevity) in the List is incremented, TextView should update in onChanged to display the first value in the List.

Goals

  • Increment first value in a List
  • Update TextView when first item of a List changes

Problem

  1. On Button click, the first value in the List is incremented but MutableLiveData.onChanged() isn't called, why is this?
  2. Does MutableLiveData only respond to its setValue method?
  3. Could this be solved via the List containing MutableLiveData Integers (i.e., MutableLiveData<List<MutableLiveData<Integer>>, problematic since requires listeners for each item in the List)?
  4. Is there a better way to achieve the goals?

Code

final MutableLiveData<List<Integer>> vals = new MutableLiveData<>();
List<Integer> intVals = new ArrayList<>();
intVals.add(0);
vals.setValue(intVals);

tv.setText("" + vals.getValue().get(0));

vals.observe(this, new Observer<List<Integer>>() {
    @Override
    public void onChanged(@Nullable List<Integer> integers) {
        int firstVal = integers.get(0);
        Log.d(TAG, "onChanged val " + firstVal);
        tv.setText("" + firstVal);
    }
});

btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // first val in List is incremented but onChanged isn't called, why?
        int newVal = vals.getValue().get(0) + 1;
        vals.getValue().set(0, newVal);
        Log.d(TAG, "set val at index 0 to " + newVal);
    }
});

Solution

  • LiveData Observable's onChanged method is called only after calling setValue() or postValue().setValue() should be called only from main thread as postValue() should be called from different thread (onClick happens on main thread so setValue() will do). Anyway using the code below will get you what you need:

    btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // first val in List is incremented but onChanged isn't called, why?
        List<Integer> temp = vals.getValue();
        if(temp!=null) // null-safety just in case....
        {
            int newVal = temp.get(0) + 1;
            temp.set(0, newVal);
            vals.setValue(temp);
            Log.d(TAG, "set val at index 0 to " + newVal);
        }
    }
    });