观察多个LiveData和MVVM结构Android Java



我会尽可能地把这个问题概括起来。

简而言之,我使用的是FireStore Firebase,我想做的是我有两个存储库(TransactionsRepository和VaultAccountRepository(,每个存储库都有一些查询要添加(Transaction或VaultAccount对象(、编辑、删除等

我制作了第三个存储库(OperationRepository(,我想(例如(在其中获取所有交易,并让默认帐户对其进行操作(比如将所有交易金额与帐户初始值相加等等(,然后将该操作作为活动数据获取,以便在视图中观察它。

这里的想法是,我不知道如何观察交易和默认帐户来更新返回的操作,从而更新UI

我读过关于Transformation.mapTransformation.switchMap的文章,但我根本无法理解它们,大多数例子都在Kotlin,我甚至不确定这是否是我想要做的!并且不确定这个结构是否正确,因为我是MVVM的新手。

我将包含一些代码,以显示我试图做的事情,以防我上面的解释不够清楚。

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;
}

}

旧的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;
}

}

更新:我将OperationRepository更改为OperationVeiwModel,并尝试使用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;
});
}
}

代码没有按我的预期工作,这表明我不知道自己在做什么。

尽管如此,我还是尝试测试了这段代码,发现了以下内容:
1-当我第一次调用getFinalAmount并在视图中观察它时,这两个存储库返回null,但如果我对观察到的LiveData进行了更改,它们会返回我想要获得的实时数据。

2-transforms方法内部的switchMap根本不起作用。

我在另一个问题中找到了问题的解决方案(因此我的问题将被视为重复问题(。

(我的问题的(解决办法可以在这里找到。我需要的是一个MediatorLiveData,将我的两个实时数据合并为一个实时数据并进行观察

信用归于@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));
});
}
}

最新更新