RecyclerView IndexOutOfBoundsException

Why is the exception thrown when I deleted some elements in the RecyclerView using a loop? I used Collentions.synchronizedMap in the adapter, and the deleteItem method also used synchronization (the method in the fragment).

 public void elementController(JsonObject jsonObject , String type) { if ( jsonObject == null || type == null ) { return; } int position =0 , resultPosition =0; if ( type.equals("update") || type.equals("delete")) { String id = jsonObject.get(ELEMENT_ID).getAsString(); Map<String , Element> map = gridFragment.getMap(); synchronized (map) { for (String s : map.keySet()) { if (s.equals(id)) { resultPosition = position; } else { position++; } } } } if(position-1 > gridFragment.getmAdapter().getData().size() || position <0) { return; } switch (type) { case "add": if (gridFragment.addElement(MyJsonParser.ElementParse(jsonObject),0)){ LogUtils.logDebug(TAG,"add end"); } break; case "update": if(gridFragment.updateElement( updateParser(jsonObject),resultPosition)){ LogUtils.logDebug(TAG,"update end"); } break; case "delete": if(gridFragment.deleteElement(jsonObject.get(ELEMENT_ID).getAsString(),resultPosition)){ LogUtils.logDebug(TAG,"delete end"); } break; } } 

 public boolean deleteElement(final String id , final int position){ new Thread(new Runnable() { @Override public void run() { getActivity().runOnUiThread(new Runnable(){ @Override public void run() { synchronized (map) { map.remove(id); mAdapter.setData(map); mAdapter.notifyItemRemoved(position); } } }); } }).start(); return true; } 

My error log:

 java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 0(offset:0).state:4 at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3382) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3340) at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1810) at android.support.v7.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:356) at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1269) at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:523) at android.support.v7.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:151) at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1942) at android.support.v7.widget.RecyclerView.resumeRequestLayout(RecyclerView.java:1171) at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:167) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761) at android.view.Choreographer.doCallbacks(Choreographer.java:574) at android.view.Choreographer.doFrame(Choreographer.java:543) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747) at android.os.Handler.handleCallback(Handler.java:733) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:212) at android.app.ActivityThread.main(ActivityThread.java:5137) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:718) at dalvik.system.NativeStart.main(Native Method) 

device not found

+5
source share
4 answers

Do not read your code because I am not familiar with the classes you use, but I know how to fix this problem. The problem occurs when the deleted row item is not the last due to an index mismatch between the catalytic index (your ArrayList for storing data) and the final int position parameter in mehod onBindViewHolder . Let me explain the problem graphically:

enter image description here

Suppose we have a RecyclerView with three rows, and we delete the 3rd row in the datalist 2 index (note that the deleted one is not the last element) after removing the datalist index for the last element reduces 3 out of 2, however, final int position still retrieving its positon as 3, and this causes a problem. Thus, after deletion, you cannot use final int position as the index of the element to be removed from the datalist.

To fix this, enter int shift=0 and in the while loop, try deleting the third element in position (position shift), and if it does not work (in my case, it will) increase the offset and try to delete it again until an exception occurs.

  public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { ... holder.removeButton.setOnClickListener(new View.OnClickListener(){ //button used to remove rows @Override public void onClick(View view) { if (position == dataList.size() - 1) { // if last element is deleted, no need to shift dataList.remove(position); notifyItemRemoved(position); } else { // if the element deleted is not the last one int shift=1; // not zero, shift=0 is the case where position == dataList.size() - 1, which is already checked above while (true) { try { dataList.remove(position-shift); notifyItemRemoved(position); break; } catch (IndexOutOfBoundsException e) { // if fails, increment the shift and try again shift++; } } } } }); ... } 
+3
source
  mAdapter.notifyItemRemoved(position); 

it only notifies watchers who are listening for layout changes.

Instead, try calling:

 mAdpater.nofityDataChanged() 
+3
source

Yes, this is due to concurrency access. I came across this. Easy fix with Iterator or with a good trick: you start removing from the last item. However, ZA order with Iterator better.

I recently improved and created a FlexibleAdapter that uses this solution. Please also check out the description and the full working example: https://github.com/davideas/FlexibleAdapter

+2
source

I use the handler and call method in the adapter.

 List.delete (position); notifyitemremoved (position); notifydatachanged (); 
0
source

All Articles