MVVM – MediatorLiveData onChanged not being called

I’m not sure where I’m implementing MediatorLiveData incorrectly.

I have a Repository class that exposes a mutable live data object:

private MutableLiveData<List<UserTransaction>> mTransactionsLiveData
        = new MutableLiveData<>();

public MutableLiveData<List<UserTransaction>> getTransactionsLiveData() {
    return mTransactionsLiveData;
}

I have passed reference of this MutableLiveData to my ViewModel class with a getter:

public class UserTransactionsViewModel extends AndroidViewModel {

    private LiveData<List<UserTransaction>> mTransactionsLiveData;
    private SharedRepo                      mRepo;

    public UserTransactionsViewModel(@NonNull Application application) {
        super(application);

        mRepo = new SharedRepo(application);
        mTransactionsLiveData = mRepo.getTransactionsLiveData();
    }

    public LiveData<List<UserTransaction>> getTransactionsLiveData() {
        return mTransactionsLiveData;
    }

    public void getUserTransactions(int userId) {
        mRepo.getUserTransactions(userId);
    }


}

And in my Fragment class, I am observing it:

mViewModel.getTransactionsLiveData().observe(getViewLifecycleOwner(), new Observer<List<UserTransaction>>() {
            @Override
            public void onChanged(List<UserTransaction> list) {

                //Observing it here

                loadDataIntoRecycler(list);
            }
        });

Where I am confused:

I am now trying to add a MediatorLiveData to format the Data that the ViewModel receives from the Repository class.

So I first added a new new MediatorLiveData<>() in the ViewModel

private MediatorLiveData<List<UserTransaction>> mediatorLiveData
        = new MediatorLiveData<>();

and attached the .addSource

private MediatorLiveData<List<UserTransaction>> mediatorLiveData = new MediatorLiveData<>();

public UserTransactionsViewModel(@NonNull Application application) {
        super(application);

        mRepo = new SharedRepo(application);
        mTransactionsLiveData = mRepo.getTransactionsLiveData();
        
        mediatorLiveData.addSource(mTransactionsLiveData, new Observer<List<UserTransaction>>() {
            @Override
            public void onChanged(List<UserTransaction> userTransactions) {
                 Log.d(TAG, "onChanged: Formatting data...");

                 for(int i = 0; i < list.size(); i++){
                    list.get(i).setTime("Changing time");
                }
            }
        });
    }

I am confused, do I make the observer in the Fragment listen to the MediatorLiveData, instead of the LiveData? Because the .onChanged method on mediatorLiveData is never called.

Answer

  1. The .onChanged method on the mediatorLiveData is never called because it’s not observed.

  2. And, if you have already tried to observe the mediatorLiveData from the Fragment and .onChanged method is still not called, it means the observee is never changed. Never changed means never being setValue or postValue.

Like this:

mediatorLiveData.addSource(mTransactionsLiveData,
        new Observer<List<UserTransaction>>() {
            @Override
            public void onChanged(List<UserTransaction> userTransactions) {
                Log.d(TAG, "onChanged: Formatting data...");

                for(int i = 0; i < list.size(); i++){
                    list.get(i).setTime("Changing time");
                }

                mediatorLiveData.setValue(list);
            }
        });

Or, using Transformations.map (and Java 8 lambda) may be cleaner (while observe userTransactions from the Fragment):

public LiveData<List<UserTransaction>> userTransactions;

userTransactions = Transformations.map(mTransactionsLiveData, list -> {
            Log.d(TAG, "onChanged: Formatting data...");

            for(int i = 0; i < list.size(); i++){
                list.get(i).setTime("Changing time");
            }
            return list;
        });

Leave a Reply

Your email address will not be published. Required fields are marked *