There is a method in which I process a click on an element:

override fun onListItemClick(itemIndex: Int, itemCode: String) { presenter.onItemClick(adapter.getItem(itemIndex)) } 

But the problem is that the user somehow managed to click on the -1 element. What gave me the error:

"backtrace" => "[\" java.lang.ArrayIndexOutOfBoundsException: length \ u003d25; index \ u003d-1 \ ", \" at java.util.ArrayList.get (ArrayList.javaUE10) \ ", \" 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=72) \ ", \" at com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:945) \ ", \" at com.android.in ternal.os.ZygoteInit.main (ZygoteInit.java:740) \ "]",

How is this possible? And how to exclude the moment when the user clicks on the -1 list item?

In one of the places where I use this method:

  titleView.setOnClickListener { listener?.onListItemClick(adapterPosition, "") } 

I switched to the implementation of adapterPosition and saw the following:

/ ** * Returns the Adapter by the ViewHolder. *

If you’re not happy, you’ll not be able to do this. *

* RecyclerView doesn’t handle the next layout traversal. This can be a temporary, inconsistencies and adapter contents have. This is not the case since it will be less than 16ms. Sometimes, you may need to make it. In this case, you should calculate the position of the ViewHolder. *

* Note that if you’ve called {@link RecyclerView.Adapter # notifyDataSetChanged ()}, until the * next layout pass, you will {@link #NO_POSITION}. If it still exists in the adapter. * {@link RecyclerView # NO_POSITION} if the item has been removed from the adapter, * {@link RecyclerView.Adapter # notifyDataSetChanged ()} has the name has been already recycled. * /

Maybe somewhere there is a problem? So how exactly is this method returning -1.

 public final int getAdapterPosition() { if (mOwnerRecyclerView == null) { return NO_POSITION; } return mOwnerRecyclerView.getAdapterPositionFor(this); } 
  • 3
    Delete, well, like this: if (itemIndex < 0) return; . And in order to understand how it happened, you need to look at the code that calls onListItemClick . - eugeneek
  • But can it be that the -1 index is the last item in the list (-2 is the last but one, etc.)? :) - gil9red
  • @ gil9red but I don’t know honestly. And how can I see this? - Inkognito
  • one
    Without a code that is associated with a problem (getting an index), no one will tell you anything intelligible. The code in the question is not directly related to the problem, but is its consequence (the resulting index is out of range) - pavlofff
  • @pavlofff then you should also show the code where this method is used? - Inkognito

2 answers 2

When getting the position in the adapter list via the getAdapterPosition() method, there are situations when the RecyclerView adapter returns the NO_POSITION value (the value of the constant -1), for example, when a click on the item occurred during the list update. This situation needs to be handled separately, for example (to perform actions on a click on an item only when the position is not equal to 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; } } } 

or use the getLayoutPosition() method, which also has its drawbacks (the position does not always correspond to the actual under certain circumstances).

For more information, see offdocumentation (section Positions in RecyclerView)

  • It sounds very logical, but the catch is, how can I check that everything works as it should? Well, that is, yes, the code shows that the element should not be -1, but is that enough? - Inkognito
  • @Inkognito yes, enough. with no_position, nothing will happen. Testing is rather problematic due to the specifics of the manifestation, but when using such a solution, no drop on the -1 index was noticed. - pavlofff
  • Well, the last clarifying question, in holdere, it turns out to be implemented without problems, but what if I want to implement this condition in the onListItemClick method itself, how can I refer to getAdapterPosition ()? - Inkognito
  • @Inkognito is highly discouraged from returning an invalid position from the adapter, and then trying to get around it, the only thing you can get is more code for checks that can be avoided. If you really want to, then you do not need to call the getAdapterPosition () method in the callback - in the adapter it returns -1, you will get this value through the callback and fight it as you like (what you have and now, judging throughout). - pavlofff

I would have advised to wrap the method in try-catch before identifying the problem:

 override fun onListItemClick(itemIndex: Int, itemCode: String) { try { presenter.onItemClick(adapter.getItem(itemIndex)) } catch (e: Exception) { } } 
  • Generally in the catch block it would be nice to display error logs, something like:

    e.log ()

And already in it you implement the method of getting the error (something like this).

  • Well, as I understand it, this is equivalent to writing an if (itemIndex <0) return only additionally with an error output? And it is possible more in detail about an error conclusion. - Inkognito
  • Exactly. Regarding the method that will produce an error, it is better to ask a new question, I think. - Morozov
  • The full no write of the template is never enough for the description of the error itself, which can be obtained using e.log() . - Flippy
  • @Flippy did not quite understand your comment) what exactly did you want to say?) - Morozov
  • @Flippy never enough? Tipo enough will be the default method? or I misunderstood? - Inkognito