Страницы

Поиск по вопросам

среда, 12 июня 2019 г.

адаптер RecyclerView возвращает позицию -1

Есть метод, в котором обрабатываю нажатие по элементу:
override fun onListItemClick(itemIndex: Int, itemCode: String) { presenter.onItemClick(adapter.getItem(itemIndex)) }
Но проблема в том, что пользователь как то умудрился нажать на -1 элемент. Что выдало мне ошибку:
"backtrace" => "[\"java.lang.ArrayIndexOutOfBoundsException: length\u003d25; index\u003d-1\",\" at java.util.ArrayList.get(ArrayList.java:310)\",\" at com.project.android.features.common.base_list.AbstractListAdapter.getItem(AbstractListAdapter.kt:20)\",\" at com.project.android.features.categories.selector.CategorySelectDialog.onListItemClick(CategorySelectDialog.kt:59)\",\" at com.project.android.features.categories.selector.CategorySelectItemViewHolder$1.onClick(CategorySelectItemViewHolder.kt:32)\",\" at android.view.View.performClick(View.java:4856)\",\" at android.view.View$PerformClick.run(View.java:19956)\",\" at android.os.Handler.handleCallback(Handler.java:739)\",\" at android.os.Handler.dispatchMessage(Handler.java:95)\",\" at android.os.Looper.loop(Looper.java:211)\",\" at android.app.ActivityThread.main(ActivityThread.java:5371)\",\" at java.lang.reflect.Method.invoke(Native Method)\",\" at java.lang.reflect.Method.invoke(Method.java:372)\",\" at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:945)\",\" at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:740)\"]",
Как такое возможно? И как исключить момент нажатия пользователя на -1 элементе списка?
В одном из мест где использую данный метод:
titleView.setOnClickListener { listener?.onListItemClick(adapterPosition, "") }
Перешёл к реализации adapterPosition и увидел следующее:
/** * Returns the Adapter position of the item represented by this ViewHolder. * * Note that this might be different than the {@link #getLayoutPosition()} if there are * pending adapter updates but a new layout pass has not happened yet. * * RecyclerView does not handle any adapter updates until the next layout traversal. This * may create temporary inconsistencies between what user sees on the screen and what * adapter contents have. This inconsistency is not important since it will be less than * 16ms but it might be a problem if you want to use ViewHolder position to access the * adapter. Sometimes, you may need to get the exact adapter position to do * some actions in response to user events. In that case, you should use this method which * will calculate the Adapter position of the ViewHolder. * * Note that if you've called {@link RecyclerView.Adapter#notifyDataSetChanged()}, until the * next layout pass, the return value of this method will be {@link #NO_POSITION}. * * @return The adapter position of the item if it still exists in the adapter. * {@link RecyclerView#NO_POSITION} if item has been removed from the adapter, * {@link RecyclerView.Adapter#notifyDataSetChanged()} has been called after the last * layout pass or the ViewHolder has already been recycled. */
Возможно где то тут кроется проблема? Так как именно в этом методе возвращается -1.
public final int getAdapterPosition() { if (mOwnerRecyclerView == null) { return NO_POSITION; } return mOwnerRecyclerView.getAdapterPositionFor(this); }


Ответ

При получении позиции в списке адаптера через метод getAdapterPosition(), возможны ситуации, когда адаптер RecyclerView возвращает значение NO_POSITION (значение константы -1), например, когда клик по айтему произошел во время обновления списка. Такую ситуацию нужно обрабатывать отдельно, например так (совершать действия по клику на айтеме только когда позиция не равна NO_POSITION):
@Override public void onClick(View v) { int position = getAdapterPosition(); if (position != RecyclerView.NO_POSITION) { switch (v.getId()) { case R.id.menu_button: // break; case R.id.card: // break; } } }
или использовать метод getLayoutPosition(), который тоже имеет свои недостатки (позиция не всегда соответствует действительной при определенных обстоятельствах).
Подробнее смотрите офф.документацию (раздел Positions in RecyclerView)

Комментариев нет:

Отправить комментарий