В 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 шт):

Автор решения: lavdev4

Нашел решение сам. Отчасти это была моя невнимательность, отчасти глюк. Если говорить о первом, то я забыл, что у меня включается анимация при обновлении списка и заканчивается по окончанию этого процесса, отсюда были моргания интерфейса которые ввели меня в заблуждение, что у меня обновляется весь список целиком. А глюк был в том, что в 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.

→ Ссылка