简体   繁体   中英

How can LiveData in ViewModel observe the Livedata in Repository using Transformations?

I am using an AsyncTask in my repository which is used to set the LiveData in the repository. How do I observe this LiveData from my ViewModel using Transformations?

You can ignore my other answer. The solution is using MediatorLiveData<> in your view model. You add the LiveData from the repository as a data source to the MediatorLiveData<> and call setValue or postValue (depends on if it is in the UI tread or not) in the observer onChanged callback.

Like so

    currentTransaction.addSource(application.getFinanceRepository().getTransaction(id),
            new Observer<Transaction>() {
        @Override
        public void onChanged(@Nullable Transaction transaction) {
            //Updates the MediatorLiveData<> that you activity is observing
            currentTransaction.setValue(transaction);
        }
    });

So I was trying just this thing today and couldn't get it to work. I tried both

Transformations.switchMap(application.getFinanceRepository().getTransaction(id),
            new Function<Transaction, LiveData<Transaction>>() {
                @Override
                public LiveData<Transaction> apply(Transaction input) {
                    Log.d(TAG, "apply: VIewModel Transaction changed: " + input.toString());
                    //Set the inital transaction to track changes
                    initialTransaction = input;

                    //Update the transaction observed by the activity/fragment
                    currentTransaction.setValue(input);
                    return currentTransaction;
                }
            });

and

Transformations.map(loading,
            new Function<Transaction, Object>() {
                @Override
                public Object apply(Transaction input) {
                    //Set the inital transaction to track changes
                    initialTransaction = new Transaction(input);

                    //Update the transaction observed by the activity/fragment
                    currentTransaction.setValue(input);
                    return null;
                }
            });

where currentTransaction is a MutableLiveData and initalTransaction is just a Transaction object. application.getFinanceRepository().getTransaction(id) returns a LiveData

This compiled fine but didn't run properly. apply() was never called and I was left with a null Transaction. I couldn't figure out how to get it to load something.

As a work around to get it working I returned application.getFinanceRepository().getTransaction(id) back to the fragment/activity. The observer for this would then call a method in the viewModel to give Transaction back to the view model

public void transactionLoaded(Transaction transaction) {
    initialTransaction = new Transaction(transaction);
    currentTransaction.setValue(transaction);
}

I then also set the activity to also observe currentTransaction the MutableLiveData

Some more snippets to hopefully clear up what I did.

Fragment.java onActivityCreated()

    viewModel.loadTransaction(id).observe(this, new Observer<Transaction>() {
        @Override
        public void onChanged(@Nullable Transaction transaction) {
            viewModel.transactionLoaded(transaction);
        }
    });

    viewModel.getTransaction().observe(this, new Observer<Transaction>() {
        @Override
        public void onChanged(@Nullable Transaction trans) {
            //When new LiveData arrives update the transaction and then the views
            Log.d(TAG, "onChanged: transaction changed: " + trans.toString());
            transaction = trans;
            updateViews();
        }
    });

TransactionViewModel.java relevant portions

private Transaction initialTransaction;
private final MutableLiveData<Transaction> currentTransaction = new MutableLiveData<>();

public LiveData<Transaction> loadTransaction(int id) {
    return application.getFinanceRepository().getTransaction(id);
}


public void transactionLoaded(Transaction transaction) {
    initialTransaction = new Transaction(transaction);
    currentTransaction.setValue(transaction);
}

It isn't ideal because it won't work unless the fragment/activity participates but it does function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM