RecyclerView ItemTouchHelper getAdapterPosition() возвращает неправильное значение при быстром пролистывании

У меня проблема с RecyclerView + Swipe для удаления + отмены с помощью снэк-бара. Всякий раз, когда я пытаюсь быстро пролистать 3+ предметов, чтобы удалить их, viewHolder.getAdapterPosition(); возвращает неправильное значение. Похоже, он не может реагировать так быстро.

RecyclerView list Пример:

  1. Test1
  2. Test2
  3. Test3
  4. Test4

Итак, если я быстро проведу пальцем по Test3, Test2, а затем Test1 viewHolder.getAdapterPosition(); возвращает позиции 2, 2 и затем 0. Правильный возврат должен быть 2, 1, а затем 0.

Для двух элементов все ведет себя нормально, возвращает 2, а затем 1.

Примечание: последняя позиция всегда возвращается через 2 секунды, потому что тайм-бар истекает, а затем элемент удаляется. Закусочные, которые показываются раньше, закрываются, как только следующий предмет удаляется.

Есть идеи как решить это? Я пытался понять это в течение нескольких часов.

ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            return false;
        }

        @Override
        public void onSwiped(final RecyclerView.ViewHolder viewHolder, int swipeDir) {

            final int position = viewHolder.getAdapterPosition();

            FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
            rusure = Snackbar.make(fab, getResources().getString(R.string.rule_deleted), Snackbar.LENGTH_SHORT).addCallback(new Snackbar.Callback() {
                @Override
                public void onDismissed(Snackbar snackbar, int event) {

                    switch(event) {
                        case Snackbar.Callback.DISMISS_EVENT_ACTION:
                            rulesAdapter.notifyDataSetChanged();
                            break;
                        case Snackbar.Callback.DISMISS_EVENT_TIMEOUT:
                        case Snackbar.Callback.DISMISS_EVENT_CONSECUTIVE:
                        case Snackbar.Callback.DISMISS_EVENT_MANUAL:

                            Log.d("test", Integer.toString(position));
                            if(position!=-1 && position<arrayList.size()){

                                // Define 'where' part of query.
                                String selection = DatabaseTablesColums.FeedEntry._ID + " LIKE ?";
                                // Specify arguments in placeholder order.
                                String[] selectionArgs = {Integer.toString(arrayList.get(position).getId())};
                                // Issue SQL statement.


                                arrayList.remove(position);
                                rulesAdapter.notifyItemRemoved(position);
                                rulesAdapter.notifyItemRangeChanged(position, rulesAdapter.getItemCount());


                                db.delete(DatabaseTablesColums.FeedEntry.TABLE_NAME, selection, selectionArgs);
                                // Remove item from backing list here
                            }

                            break;
                    }
                }

                @Override
                public void onShown(Snackbar snackbar) {
                }
            }).setAction(getResources().getString(R.string.undo), new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                }
            });
            rusure.show();


        }
    });

    itemTouchHelper.attachToRecyclerView(recyclerView);

1 ответ

Решение

Похоже, вы удаляете элемент из резервного хранилища данных, в вашем случае это arrayList и уведомляет адаптер только после отклонения SnackBar.

Таким образом, если вы проведете пальцем по следующему элементу до того, как будет снят первый снэк-бар, адаптер RecyclerView не поймет, что первый элемент был удален из адаптера. Так что это дает вам неправильную позицию.

Вы должны удалить элемент из резервного хранилища данных (arrayList) и вызвать notifyItemRemoved() как только вы проведете предмет, а не обновите его после того, как снэк-бар исчезнет.

Вы можете обновить базу данных только после закрытия SnackBar.

Другие вопросы по тегам