В onBindViewHolder у адаптера ListAdapter приходит пустой payloads
Вот мой ListAdapter с DiffUtil:
public class EditListAdapter extends ListAdapter<Test, EditListAdapter.EditListViewHolder> {
private final EditListButtonClickListener buttonClickListener;
public interface EditListButtonClickListener {
void onButtonClick(Test test);
}
public EditListAdapter(@NonNull DiffUtil.ItemCallback<Test> diffCallBack, EditListButtonClickListener buttonClickListener) {
super(diffCallBack);
this.buttonClickListener = buttonClickListener;
}
@NonNull
@Override
public EditListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_edit_list, parent, false);
return new EditListViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull EditListViewHolder holder, int position) {
Test test = getCurrentList().get(position);
String quantity = Integer.toString(test.quantity);
holder.nameView.setText(test.getTestName());
holder.quantityView.setText(quantity);
Test newTest = new Test(test.getDepartmentId(), test.getTestName());
newTest.id = test.id;
newTest.quantity = test.quantity;
holder.addTest.setOnClickListener(view -> {
newTest.quantity++;
buttonClickListener.onButtonClick(newTest);
});
holder.removeTest.setOnClickListener(view -> {
if (newTest.quantity > 0) {
newTest.quantity--;
}
buttonClickListener.onButtonClick(newTest);
});
}
@Override
public void onBindViewHolder(@NonNull EditListViewHolder holder, int position, @NonNull List<Object> payloads) {
if (!payloads.isEmpty()) {
int quantity = ((Bundle) payloads.get(0)).getInt("NEW_QUANTITY");
String strQuantity = Integer.toString(quantity);
holder.quantityView.setText(strQuantity);
} else {
super.onBindViewHolder(holder, position, payloads);
}
}
public static class EditListViewHolder extends RecyclerView.ViewHolder {
private final TextView nameView, quantityView;
private final Button addTest, removeTest;
private EditListViewHolder(@NonNull View itemView) {
super(itemView);
nameView = itemView.findViewById(R.id.edit_list_fragment_adapter_test_name);
quantityView = itemView.findViewById(R.id.edit_list_fragment_adapter_tests_quantity);
addTest = itemView.findViewById(R.id.edit_list_fragment_adapter_add_button);
removeTest = itemView.findViewById(R.id.edit_list_fragment_adapter_remove_button);
}
}
public static class EditListDiffUtil extends DiffUtil.ItemCallback<Test> {
@Override
public boolean areItemsTheSame(@NonNull Test oldItem, @NonNull Test newItem) {
return oldItem.id == newItem.id;
}
@Override
public boolean areContentsTheSame(@NonNull Test oldItem, @NonNull Test newItem) {
return oldItem.quantity == newItem.quantity;
}
@Nullable
@Override
public Object getChangePayload(@NonNull Test oldItem, @NonNull Test newItem) {
Bundle changedPayload = new Bundle();
if (oldItem.quantity != newItem.quantity) {
changedPayload.putInt("NEW_QUANTITY", newItem.quantity);
}
return changedPayload;
}
}
}
И вот как происходит вызов submitList() у адаптера:
model.getSpinnerSelectedItem().observe(getViewLifecycleOwner(), spinnerSelectedItem ->
disposables.add(model.getTodayTestsList()
.subscribeWith(new DisposableObserver<List<Test>>() {
@Override
public void onNext(@NonNull List<Test> tests) {
editListAdapter.submitList(tests);
}
@Override
public void onError(@NonNull Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
}
})));
Тут надо пояснить, что при каждом нажатии на кнопку у элемента списка происходит инкремент параметра (quantity) и передача этого элемента в базу данных для обновления, после чего Flowable получает список этих элементов и обновляет список на экране передавая новый список с изменениями через submitList().
Моя проблема в том, что в onBindViewHolder(@NonNull EditListViewHolder holder, int position, @NonNull List<Object> payloads) у адаптера приходит пустой массив payloads, хотя getChangePayload срабатывает и из него уходит заполненный Bundle, я проверил.
Пробовал делать recyclerView.setItemAnimator(null), не помогло.
Ответы (1 шт):
Нашел решение сам. Отчасти это была моя невнимательность, отчасти глюк. Если говорить о первом, то я забыл, что у меня включается анимация при обновлении списка и заканчивается по окончанию этого процесса, отсюда были моргания интерфейса которые ввели меня в заблуждение, что у меня обновляется весь список целиком. А глюк был в том, что в debug режиме AndroidStudio показывал мне, что payloads приходит пустым, что было опровергнуто логированием блока кода:
if (!payloads.isEmpty()) {
int quantity = ((Bundle) payloads.get(0)).getInt("NEW_QUANTITY");
String strQuantity = Integer.toString(quantity);
holder.quantityView.setText(strQuantity);
По итогу все работает, можно даже ничего не принимать и не обрабатывать в onBindViewHolder с параметром payloads, достаточно только оформить getChangePayload и чтобы он возвращал какойто любой объект. Почему гугл не сделал этот метод абстрактным я не знаю, два дня голову ломал прежде чем узнал про него, в исходном коде он просто возвращает null.