Я добавил флажок и библиотеку подкачки в кодовую метку Google RoomWithAView, и вызов DiffUtil.ItemCallback, похоже, передает обновленную версию сущности как параметрам oldItem, так и newItem.
Мое проверенное состояние флажка управляется логическим полем в базе данных с именем isSelected, которое обновляется при щелчке строки, и это должно привести к изменению состояния флажка.
Проблема заключается в том, чточто при обновлении поля «isSelected» (например, с false на true) следующая печать журнала возвращает true для обоих элементов.Мое состояние флажка не изменяется, потому что areContentsTheSame возвращает true, а onBindViewHolder не вызывается.Я могу заставить это вернуть false, но я хочу понять, что происходит не так:
private static DiffUtil.ItemCallback<WordEntity> DIFF_CALLBACK =
new DiffUtil.ItemCallback<WordEntity>() {
@Override
public boolean areItemsTheSame(WordEntity oldItem, WordEntity newItem) {
Log.i("CLEAN_LOG","areItemsTheSame: " +
Boolean.toString(oldItem.getWordId()==newItem.getWordId()));
return oldItem.getWordId() == newItem.getWordId();
}
@Override
public boolean areContentsTheSame(WordEntity oldItem, WordEntity newItem) {
Log.i("CLEAN_LOG","oldItem: " +
Boolean.toString(oldItem.getIsSelected()));
Log.i("CLEAN_LOG","newItem: " +
Boolean.toString(newItem.getIsSelected()));
Log.i("CLEAN_LOG","areContentsTheSame: " +
Boolean.toString(oldItem.getIsSelected() == newItem.getIsSelected()));
return oldItem.getIsSelected() == newItem.getIsSelected();
}
};
Вот мой PagedListAdapter:
public static class WordListAdapter extends PagedListAdapter<WordEntity, WordListAdapter.WordViewHolder> {
protected WordListAdapter() {
super(DIFF_CALLBACK);
setHasStableIds(true);
}
@NonNull
@Override
public WordViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recyclerview_item, parent, false);
return new WordViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull WordViewHolder holder, int position) {
WordEntity current = getItem(position);
if (current != null) {
holder.bindTo(current);
}
}
private static DiffUtil.ItemCallback<WordEntity> DIFF_CALLBACK =
new DiffUtil.ItemCallback<WordEntity>() {
@Override
public boolean areItemsTheSame(WordEntity oldItem, WordEntity newItem) {
Log.i("CLEAN_LOG","areItemsTheSame: " +
Boolean.toString(oldItem.getWordId()==newItem.getWordId()));
return oldItem.getWordId() == newItem.getWordId();
}
@Override
public boolean areContentsTheSame(WordEntity oldItem, WordEntity newItem) {
Log.i("CLEAN_LOG","oldItem: " +
Boolean.toString(oldItem.getIsSelected()));
Log.i("CLEAN_LOG","newItem: " +
Boolean.toString(newItem.getIsSelected()));
Log.i("CLEAN_LOG","areContentsTheSame: " +
Boolean.toString(oldItem.getIsSelected() == newItem.getIsSelected()));
return oldItem.getIsSelected() == newItem.getIsSelected();
}
};
@Override
public long getItemId(int position) {
WordEntity current = getItem(position);
return current.mWordId;
}
class WordViewHolder extends RecyclerView.ViewHolder {
TextView wordItemView;
CheckBox checkBox;
LinearLayout viewForeground;
public void bindTo(WordEntity word) {
wordItemView.setText(word.mWord);
checkBox.setChecked(word.mIsSelected);
}
private WordViewHolder(View itemView) {
super(itemView);
viewForeground = itemView.findViewById(R.id.viewForeground);
wordItemView = itemView.findViewById(R.id.textView);
checkBox = itemView.findViewById(R.id.checkBox);
checkBox.setClickable(false);
viewForeground.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
final WordEntity thisWord = getItem(getAdapterPosition());
if (thisWord != null) {
Toast.makeText(context,
"You long-clicked: " + thisWord.getWord(),
Toast.LENGTH_LONG).show();
}
// returning false here will alow onClickListener to trigger as well
return true;
}
});
viewForeground.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final WordEntity thisWord = getItem(getAdapterPosition());
if (thisWord != null) {
if (thisWord.getIsSelected()) {
thisWord.setIsSelected(false);
} else {
thisWord.setIsSelected(true);
}
mWordViewModel.update(thisWord);
}
}
});
}
}
}
Вот мой наблюдатель:
mWordViewModel = ViewModelProviders.of(this).get(WordViewModel.class);
mWordViewModel.getAllWords().observe(this, new Observer<PagedList<WordEntity>>() {
@Override
public void onChanged(@Nullable final PagedList<WordEntity> words) {
// Update the cached copy of the words in the adapter.
adapter.submitList(words);
if (words != null) {
wordCount = words.size();
} else {
wordCount = 0;
}
Log.i(LOG_TAG,"Word Count: " + Integer.toString(wordCount));
}
});
- Все обновления базы данных комнат происходят правильно
- На основе журнала создается впечатление, что areItemsTheSame вызывается дважды при нажатии строки, а areContentsTheSame вызывается один раз
Я ожидал, что oldItem.getIsSelected () будет false, а new.Item.getIsSelected () будет true, а затем будет запущен onBindViewHolder.Я также ожидал, что isItemsTheSame и areContentsTheSame будут вызывать только один раз для каждого элемента.
Может ли кто-нибудь помочь мне понять, что здесь происходит неправильно, и соответствуют ли мои ожидания тому, что должно происходить ?
Вот GitHub с моим примером приложения: https://github.com/DanglaGT/RoomWithAViewPaging