RecyclerView IndexOutOfBoundsException [英] RecyclerView IndexOutOfBoundsException

查看:294
本文介绍了RecyclerView IndexOutOfBoundsException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么使用循环删除RecyclerView中的某些项目时会执行异常? 我在适配器中使用了Collentions.synchronizedMap,而'deleteItem method'也使用了同步化(片段中的方法).

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;
} 

我的错误日志:

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)

找不到设备

推荐答案

由于我不熟悉您使用的类,但是我知道解决此问题的方法,因此尚未阅读您的代码.当删除的行元素不是最后一个元素时,由于数据列表索引(您的用于存储数据的ArrayList)与方法onBindViewHolder中的参数final int position之间的索引差异,就会出现问题.让我以图形方式说明问题:

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 mehod onBindViewHolder. Let me explain the issue in a graphical manner:

假设我们有一个包含三行的RecyclerView,并且删除后删除了数据列表索引2中的第三行(请注意,被删除的不是最后一个元素),最后一个元素的数据列表索引从2减少了3 ,final int position仍将其正数检索为3,这会引起问题.因此,删除后,您不能使用final int position作为要从数据列表中删除的元素的索引.

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 positon 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 the datalist.

要解决此问题,请引入int shift=0并在while循环中,try在(position-shift)处删除第三个项目,如果它失败了(在我的情况下,它将增加),并尝试再次将其删除直到没有例外发生.

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++;
                                }
                            }
                        }
                    }
                });
   ...
    }

这篇关于RecyclerView IndexOutOfBoundsException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆