Есть метод, в котором обрабатываю нажатие по элементу:
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)
Комментариев нет:
Отправить комментарий