[英]Livedata doesn't update data in fragment correctly
我在單獨的選項卡中有tablayout
和 2 個fragments
。 Fragment A 有一個被覆蓋的方法,當 Activity(從 Fragment A 開始)在其銷毀時返回數據時返回數據:
public class Fragment A extends Fragment {
...
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if(resultCode != RESULT_CANCELED) {
assert data != null;
String accountTransaction = data.getStringExtra("Account");
String categoryTransaction = data.getStringExtra("Category");
Double getDouble = data.getDoubleExtra("Value", 0);
TransactionNewItem item = new TransactionNewItem(String.valueOf(getDouble),accountTransaction,categoryTransaction);
model.setSelected(item);
}
super.onActivityResult(requestCode, resultCode, data);
}
}
在同樣的方法中,我調用 ViewModel 來觀察 TransactionNewItem object:
public class TransactionViewModel extends ViewModel {
private final MutableLiveData<TransactionNewItem> selected = new MutableLiveData<>();
public void setSelected (TransactionNewItem item){
selected.setValue(item);
}
public LiveData<TransactionNewItem> getSelected() {
return selected;
}
}
從 Activity 返回數據后,使用新值創建一個新 POJO,並將存儲在此 POJO 中的數據發送到 Fragment B,其中基於來自 Fragment 的數據將創建 RecyclerView 的新項目
public class Fragment B extends Fragment {
...
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
initObserve();
initRecView();
super.onViewCreated(view, savedInstanceState);
}
//init RecyclerView
private void initRecView(){
binding.transactionView.setLayoutManager(new LinearLayoutManager(requireContext()));
adapter = new TransactionRecViewAdapter(listContentArr);
adapter.setListContent(listContentArr);
binding.transactionView.setAdapter(adapter);
}
//observe data from Fragment A and create object based on it
private void initObserve(){
model = new ViewModelProvider(requireActivity()).get(TransactionViewModel.class);
model.getSelected().observe(getViewLifecycleOwner(), item -> {
TransactionItem newAccountItem = new TransactionItem() ;
newAccountItem.setTransactionValue(item.getTransactionValue());
newAccountItem.setTransactionCategory(item.getTransactionCategory());
newAccountItem.setTransactionAccount(item.getTransactionAccount());
listContentArr.add(0,newAccountItem);
adapter.notifyDataSetChanged();
});
}
}
但是,它只會將 1 個項目添加到 RecyclerView 中,並在 Activity 返回新數據時替換它。 如果用戶沒有至少一次切換到 Fragment B,就會發生這種情況,因為在用戶切換到 Fragment B 之前不會調用 onViewCreated。
如果用戶之前從未切換到 Fragment B,如何讓 ViewModel 觀察來自 Fragment A 的數據,並在每次 Activity 返回新數據時在 Fragment B Recyclerview 中創建新的 TransActionItem?
提前致謝
編輯:我設法以另一種方式做我想做的事:
步驟 1. 我使用 POJO - ArrayList 將 ViewModel 從 POJO 更改為 Arraylist:
public class TransactionViewModel extends ViewModel {
private final MutableLiveData<ArrayList<TransactionItem>> selected = new MutableLiveData<>();
public void setSelected (ArrayList<TransactionItem> arrayList){
selected.setValue(arrayList);
}
public LiveData<ArrayList<TransactionItem>> getSelected() {
return selected;
}
}
步驟 2. 在 Fragment AI 中,在 onActivityResult 中添加了具有相同 POJO 類型的 ArrayList。 我現在更改了代碼 object 將在 Activity 返回結果后創建並添加,而不是在片段 B 中:
public class Fragment A extends Fragment {
ArrayList<TransactionItem> listTransactions = new ArrayList<>();
…
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if(resultCode != RESULT_CANCELED) {
...
//Create TransactionItem and use setSelected method from ViewModel
TransactionItem item = new TransactionItem(accountTransaction,
String.valueOf(getDouble),categoryAccount),transactionID);
listTransactions.add(0,item);
model.setSelected(listTransactions);
}
super.onActivityResult(requestCode, resultCode, data);
}
}
必須注意我在 TransactionItem 構造函數中添加了 transactionID,這就是我們需要它的原因。
第 3 步我創建了下一個擴展 DiffUtil.Callback 的 TransactionDiffUtilCallback class:
public class TransactionDiffUtilCallback extends `DiffUtil.Callback` {
public TransactionDiffUtilCallback(ArrayList<TransactionItem> oldList, ArrayList<TransactionItem> newList) {
this.oldList = oldList;
this.newList = newList;
}
ArrayList<TransactionItem> newList;
@Override
public int getOldListSize() {
return oldList.size();
}
@Override
public int getNewListSize() {
return newList.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldList.get(oldItemPosition).getItemIID() == newList.get(newItemPosition).getItemIID();
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldList.get(oldItemPosition).equals(newList.get(newItemPosition));
}
@Nullable
@Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
return super.getChangePayload(oldItemPosition, newItemPosition);
}
}
我使用 POJO 的getItemIID()
來通知 ArrayList 中的新項目不同。
第 4 步在 recyclerview 適配器中,我創建了 updateItemList(list):
public void updateItemList(ArrayList<TransactionItem> items){
final TransactionDiffUtilCallback diffCallback = new TransactionDiffUtilCallback(this.pad_list, items);
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
this.pad_list.clear();
this.pad_list.addAll(items);
diffResult.dispatchUpdatesTo(this);
}
So this method uses DiffUtil.CallBack to compare items in ArrayList from Fragment A and ArrayList in Fragment B, then notify adapter that ArrayList from Fragment A is different, and this data should be put in ArrayList in Fragment B, and view should be updated.
步驟 5 在 Fragment B 中的 OnViewCreated() 代碼被重寫以永遠觀察 Arraylist:
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
initRecView();
model = new ViewModelProvider(requireActivity()).get(TransactionViewModel.class);
Observer<ArrayList<TransactionItem>> observer = (Observer<ArrayList<TransactionItem>>) this::initObserve;
model.getSelected().observeForever(observer);
super.onViewCreated(view, savedInstanceState);
}
而 initObserve() 現在有下一個代碼:
private void initObserve(ArrayList<TransactionItem> list){
adapter.updateItemList(list);
}
目前,這個解決方案正在運行,用戶不需要切換到 Fragment B 來保持交易記錄。 我將繼續測試此解決方案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.