Issue
Why exception execute when I removed some items in RecyclerView
by using loop ?
I used Collentions.synchronizedMap
in adapter and 'deleteItem method' use synchronized too (the method in 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
Solution
Haven't read your code because I'm not familiar with the classes that you use but I know a fix to this problem. The problem occurs when the row element deleted is not the last one because of the index discrepancy between dataList
index (your ArrayList to store data) and the parameter final int position
in the method onBindViewHolder
. Let me explain the issue in a graphical manner:
suppose we have a RecyclerView with three rows and we delete the 3rd row, at dataList
index 2, (note that the deleted one is not the last element) after the removal, dataList
index for the last element reduces 3 from 2 however, final int position
still retrieves its position as 3 and that causes the problem. So, after removal, you can't use final int position
as an index of element to be removed from dataList
.
To fix this, introduce int shift=0
and in a while loop, try
removing the third item at (position-shift) and if it fails (in my case, it will) increment the shift and try removing it again until no 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++;
}
}
}
}
});
...
}
Answered By - Ozan
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.