android - Android:如何将观察者用于多个过滤条件?
问题描述
我有一个 CardViews 的 RecyclerView 列表。我希望用户能够通过单击类型的不同 TextView 来根据 CardView 类型过滤列表。过滤器第一次正常工作。如果我单击 One TextView,则会过滤列表,并且视图仅显示 One 卡片。退格键将用户带回到完整列表。接下来,用户单击两个 TextView。这就是问题发生的地方,因为视图显示的是过滤后的一张卡片列表,而不是预期的两张卡片。因此观察者默认使用原始的一张卡过滤器类型,而不是预期的两张卡过滤器类型。
如果用户先选择两张卡的TextView,也会出现同样的错误。在这种情况下,只有两张卡片按预期显示在视图中。退格将用户返回到完整列表。然后单击 One TextView 再次过滤列表,但显示两张卡片而不是预期的一张卡片。
我在这里想念什么?每次单击 TextView 后,我都尝试使用 removeObserver() 和 removeObservers() 但没有运气。如何重新使用具有多个过滤条件的观察者,这样我就不必为每个过滤器设置单独的观察者,然后需要在 ViewModel、Repository 和 Dao 中使用单独的方法?
public class MainActivity extends AppCompatActivity {
// for filtering card type
final String type0 = "OneCards";
final String type1 = "TwoCards";
private List<Card> filteredModelList0 = null;
private List<Card> filteredModelList1 = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewModel = new ViewModelProvider(this).get(ViewModel.class);
}
public void onClickFilterList(View view) {
// set up an AlertDialog for the user to select a filter
final AlertDialog.Builder alertDialogFilter = new AlertDialog.Builder(MainActivity.this);
LayoutInflater inflaterFilter = getLayoutInflater();
final ViewGroup nullParent = null;
final View dialogLayoutFilter = inflaterFilter.inflate(R.layout.filter_main_aldialog, nullParent);
alertDialogFilter.setView(dialogLayoutFilter);
final AlertDialog dialogFilter = alertDialogFilter.create();
dialogFilter.show();
TextView allOnes = dialogLayoutFilter.findViewById(R.id.AllOnes);
TextView allTwos = dialogLayoutFilter.findViewById(R.id.AllTwos);
allOnes.setOnClickListener(v -> {
mViewModel.getFilteredList(type0).observe(this, filterList -> {
filteredModelList0 = filterList;
if (filterList.size() == 0) {
Toast.makeText(MainActivity.this, "There are no 'One' cards", Toast.LENGTH_SHORT).show();
filteredModelList0 = null;
} else {
cardsAdapter.setCardList(filteredModelList0);
Toast.makeText(MainActivity.this, "There are 'One' cards", Toast.LENGTH_SHORT).show();
}
});
dialogFilter.dismiss();
});
allTwos.setOnClickListener(v -> {
mViewModel.getFilteredList(type1).observe(this, filterList -> {
filteredModelList1 = filterList;
if (filterList.size() == 0) {
Toast.makeText(MainActivity.this, "There are no 'Two' cards", Toast.LENGTH_SHORT).show();
filteredModelList1 = null;
} else {
cardsAdapter.setCardList(filteredModelList1);
Toast.makeText(MainActivity.this, "There are 'Two' cards", Toast.LENGTH_SHORT).show();
}
});
dialogFilter.dismiss();
});
}
ViewModel
public class ViewModel extends AndroidViewModel {
…
private MutableLiveData<List<Card>> filteredList = null;
public LiveData<List<Card>> getFilteredList(String cardType) {
if (filteredList == null) {
filteredList = new MutableLiveData<>();
loadFilteredCards(cardType);
}
return filteredList;
}
public void loadFilteredCards(String cardType){
filteredList.postValue(repository.getFilteredCards(cardType));
}
Adapter
…
public class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public List<Card> mListItems;
…
public void setCardList(List<Card> newList) {
if (mListItems != null) {
PostDiffCallback postDiffCallback = new PostDiffCallback(mListItems, newList);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(postDiffCallback);
mListItems.clear();
mListItems.addAll(newList);
diffResult.dispatchUpdatesTo(this);
} else { // first initialization.
mListItems = newList;
}
}
}
解决方案
您的代码中有几个问题。
cardsAdapter.notifyDataSetChanged()
每次将新数据设置为适配器后调用。这种方法
public LiveData<List<Card>> getFilteredList(String cardType) {
if (filteredList == null) {
filteredList = new MutableLiveData<>();
loadFilteredCards(cardType);
}
return filteredList;
}
查看此代码。如果filteredList
为空,则用数据填充此列表 - 这是您第一次检索数据时发生的事情。第二次尝试过滤 - 你只这样做return filteredList;
- 因此你返回你已经在之前的过滤器中形成的相同列表。- 你使用的LiveData
很不正确 - 它在你的代码中作为实际数据的一些奇怪的无用代理工作。
我建议这样做
// For listeners
...
allOnes.setOnClickListener(v -> {
filteredModelList0 = mViewModel.getFilteredList(type0);
...
cardsAdapter.setCardList(filteredModelList0);
cardsAdapter.notifyDataSetChanged()
...
});
allTwos.setOnClickListener(v -> {
filteredModelList1 = mViewModel.getFilteredList(type1);
...
cardsAdapter.setCardList(filteredModelList1);
cardsAdapter.notifyDataSetChanged()
...
});
...
//For ViewModel
public class ViewModel extends AndroidViewModel {
public LiveData<List<Card>> getFilteredList(String cardType) {
return repository.getFilteredCards(cardType);
}
}
这可能需要一些额外的工作,但我希望你能做到。
编辑
如果你真的想使用这样LiveData
的编辑getFilteredList()
public LiveData<List<Card>> getFilteredList(String cardType) {
filteredList = new MutableLiveData<>();
loadFilteredCards(cardType);
return filteredList;
}
每次都重新加载它——不要检查空值。
希望能帮助到你。
推荐阅读
- python - Selenium Python 的 IE webdriver 加载网页并进入停止状态
- python - 如何使用 Selenium 和 Python 从表中的元素中提取值
- java - 使用 Stream API 和引用方法将集合对象从一种类型转换为另一种类型
- javascript - 如何在 React js 中导出组件以在另一个项目中使用?
- darklang-beta - 如何在 Darklang 中删除个人画布?
- python-3.x - 如何获取数据框中每一行的相关系数
- python - 在python中重新格式化列表
- android - 从另一个小部件 Flutter 更改文本字段的 textSize
- r - 如何映射(匹配)数据框中的列和行?
- python - 如何打印循环用户输入的总和?