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

223
29 мая 2017, 23:47

Есть метод, в котором обрабатываю нажатие по элементу:

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);
    }
Answer 1

При получении позиции в списке адаптера через метод 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)

Answer 2

Я бы до выявления проблемы, посоветовал бы обернуть метод в try-catch:

override fun onListItemClick(itemIndex: Int, itemCode: String) {
    try {
        presenter.onItemClick(adapter.getItem(itemIndex))
    } catch (e: Exception) { }
}
  • Вообще в блок catch неплохо бы выводить логи об ошибке, что то вроде:

    e.log()

А уже в нём реализуете метод получения ошибки(примерно как то так).

READ ALSO
не загружается war на Glassfish

не загружается war на Glassfish

Добавил war в application нажал launchВ итоге не работает(

223
OpenGL обновление сцены

OpenGL обновление сцены

Столкнулся со следующей проблемой: при попытке нарисовать что-либо на OpenGL после его первой прорисовке ничего не рисуетсяПробовал и glSurfaceView

176
Как вы верстаете формы(GUI)?

Как вы верстаете формы(GUI)?

Получается я для начала собирал линию 1, 2, 3

230
TextView многоточие если текст не умещается в TextView

TextView многоточие если текст не умещается в TextView

ЗдравствуйтеИмеется TextView, которая будет зажата с двух сторон другими элементами

182