Reputation: 41
I will try to make this question general as much as I can.
In short, I'm using FireStore Firebase and what I am trying to do is that I have Two Repositories (TransactionsRepository and VaultAccountRepository) and each one has some queries to add (Transaction or VaultAccount objects), edit, delete, etc...
I made a third Repository (OperationRepository) in which I want to (for example) get all transactions and get the default account to do an operation on them (like adding all the transactions amount with the account initial value and so on) and get that operation as alive data to observe it in the view.
The idea here is that I don't know how to observe the transactions and the default account to update the operation returned and consequently update the UI
I have read about Transformation.map
and Transformation.switchMap
, but I could not understand them at all and most examples are in Kotlin and I'm not even sure that it's what I'm looking for to do this! and not sure if this structure is done right as I'm new to MVVM.
I will include some of the code to show what I have tried to do just in case my explanation above wasn't clear enough.
public class VaultRepository {
...
private final MutableLiveData<VaultAccount> defaultVaultLiveData;
...
public MutableLiveData<VaultAccount> getDefaultVault() {
fireStore.collection("users").document(firebaseUser.getUid()).collection("vaults")
.whereEqualTo("defaultAccount", true)
.addSnapshotListener((value, error) -> {
VaultAccount vaultAccount = new VaultAccount();
if (value != null) {
for (QueryDocumentSnapshot doc : value) {
if (doc != null) {
vaultAccount = doc.toObject(VaultAccount.class);
}
}
defaultVaultLiveData.postValue(vaultAccount);
}
});
return defaultVaultLiveData;
}
}
public class TransactionRepository {
...
private final MutableLiveData<List<Transaction>> allTransactionsLiveData;
...
public MutableLiveData<List<Transaction>> getAllTransactions() {
fireStore.collection("users").document(firebaseUser.getUid())
.collection("transactions")
.orderBy("transactionDate")
.addSnapshotListener((value, error) -> {
List<Transaction> transactionList = new ArrayList<>();
if (value != null) {
for (QueryDocumentSnapshot doc : value) {
if (doc != null) {
Transaction transaction = doc.toObject(Transaction.class);
transactionList.add(transaction);
}
}
allTransactionsLiveData.postValue(transactionList);
}
});
return allTransactionsLiveData;
}
}
old OperationRepository
public class OperationRepository {
private final Application mApplication;
private TransactionRepository transactionRepository;
private VaultRepository vaultRepository;
private MutableLiveData<String> stringMutableLiveData;
public OperationRepository(Application mApplication) {
this.mApplication = mApplication;
transactionRepository = new TransactionRepository(mApplication);
vaultRepository = new VaultRepository(mApplication);
stringMutableLiveData = new MutableLiveData<>();
}
public MutableLiveData<String> getFinalAmount() {
//TODO get all the transactions and get there amount and observe it
// get the account initial amount and observe it
//add all the values and present it in a String LiveData to be shown in the view
double result = 0;
String finalResult = String.valueOf(result);
stringMutableLiveData.postValue(finalResult);
return stringMutableLiveData;
}
}
UPDATE:
I changed my OperationRepository to OperationVeiwModel and tried to use Transformation.switchMap
.
public class OperationViewModel extends AndroidViewModel {
private final TransactionRepository transactionRepository;
private final VaultRepository vaultRepository;
private MutableLiveData<List<Transaction>> transactionListLiveData;
private MutableLiveData<VaultAccount> vaultAccountLiveData;
private LiveData<Double> transactionTotal;
private LiveData<Double> accountAmount;
LiveData<String> totalAmount;
public OperationViewModel(@NonNull Application application) {
super(application);
transactionRepository = new TransactionRepository(application);
vaultRepository = new VaultRepository(application);
transactionListLiveData = new MutableLiveData<>();
vaultAccountLiveData = new MutableLiveData<>();
}
double result = 0;
public LiveData<String> getFinalAmount() {
transactionListLiveData = transactionRepository.getAllTransactions();
vaultAccountLiveData = vaultRepository.getDefaultVault();
transformations();
final MutableLiveData<Double> resultLive = new MutableLiveData<>();
try {
result = transactionTotal.getValue() + accountAmount.getValue();
} catch (NullPointerException e) {
Toast.makeText(getApplication(), e.getMessage(), Toast.LENGTH_LONG).show();
e.printStackTrace();
}
resultLive.postValue(result);
totalAmount = Transformations.switchMap(resultLive, data -> {
final MutableLiveData<String> result = new MutableLiveData<>();
String total = String.valueOf(data);
result.postValue(total);
return result;
});
return totalAmount;
}
private void transformations() {
transactionTotal = Transformations.switchMap(transactionListLiveData, transactionsList -> {
final MutableLiveData<Double> result = new MutableLiveData<>();
double amount = 0;
for (int i = 0; i < transactionsList.size(); i++) {
double itemAmount = Double.parseDouble(transactionsList.get(i).getTransactionAmount());
amount += itemAmount;
}
result.postValue(amount);
return result;
});
accountAmount = Transformations.switchMap(vaultAccountLiveData, vault -> {
final MutableLiveData<Double> result = new MutableLiveData<>();
result.postValue(Double.valueOf(vault.getInitAmount()));
return result;
});
}
}
The code did not work as I intended which shows that I have no idea what I'm doing.
Nevertheless, I tried to test this code and found out the following:
1- the two repositories was returning null when I first call getFinalAmount and observe it in the view but if I cause change to the observed LiveData they return the live data I want to get.
2- the switchMap inside transformations method was not working at all.
Upvotes: 1
Views: 234
Reputation: 41
I found a solution to my problem in another question (so my question will be counted as repeated).
The solution (to my problem) can be found here. What I needed was a MediatorLiveData
to combine my two live data into one live data and observe it.
Credit goes to @EpicPandaForce
public class CombinedLiveData2<A, B> extends MediatorLiveData<Pair<A, B>> {
private A a;
private B b;
public CombinedLiveData2(LiveData<A> ld1, LiveData<B> ld2) {
setValue(Pair.create(a, b));
addSource(ld1, (a) -> {
if(a != null) {
this.a = a;
}
setValue(Pair.create(a, b));
});
addSource(ld2, (b) -> {
if(b != null) {
this.b = b;
}
setValue(Pair.create(a, b));
});
}
}
Upvotes: 1