在RecyclerView中检测到不一致,如何在滚动时更改RecyclerView的内容

jim*_*251 57 android android-recyclerview

我正在使用RecyclerView显示项目的名称.我的行包含单行TextView.项目名称存储在List<String> mItemList.

要更改内容RecyclerView,我替换字符串mItemList并调用notifyDataSetChanged()RecyclerViewAdapter.

但是如果我尝试更改mItemListRecyclerView滚动时的内容,有时它会给我 java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 157(offset:157).state:588

如果尺寸mItemList小于之前,就会发生这种情况.那么改变内容的正确方法是RecyclerView什么?这是一个错误RecyclerView吗?

这是Exception的完整堆栈跟踪:

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 157(offset:157).state:588
        at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3300)
        at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3258)
        at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1803)
        at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1302)
        at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1265)
        at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1093)
        at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:956)
        at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:2715)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
        at android.view.Choreographer.doCallbacks(Choreographer.java:555)
        at android.view.Choreographer.doFrame(Choreographer.java:524)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
        at android.os.Handler.handleCallback(Handler.java:615)
        at android.os.Handler.dispatchMessage(Handler.java:92)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4921)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
        at dalvik.system.NativeStart.main(Native Method)
Run Code Online (Sandbox Code Playgroud)

AdapterView代码:

private static class FileListAdapter extends RecyclerView.Adapter<FileHolder> {
    private final Context mContext;
    private final SparseBooleanArray mSelectedArray;
    private final List<String> mList;

    FileListAdapter(Context context, List<String> list, SparseBooleanArray selectedArray) {
        mList = list;
        mContext = context;
        mSelectedArray = selectedArray;
    }


    @Override
    public FileHolder onCreateViewHolder(ViewGroup viewGroup, int i) {

        View view = LayoutInflater.from(viewGroup.getContext()).inflate(
                R.layout.file_list_item, viewGroup, false);

        TextView tv = (TextView) view
                .findViewById(R.id.file_name_text);
        Typeface font = Typeface.createFromAsset(viewGroup.getContext().getAssets(),
                viewGroup.getContext().getString(R.string.roboto_regular));
        tv.setTypeface(font);

        return new FileHolder(view, tv);
    }

    @Override
    public void onBindViewHolder(FileHolder fileHolder, final int i) {

        String name = mList.get(i);

        // highlight view if selected
        setSelected(fileHolder.itemView, mSelectedArray.get(i));

        // Set text
        fileHolder.mTextView.setText(name);
    }

    @Override
    public int getItemCount() {
        return mList.size();
    }
}

private static class FileHolder extends RecyclerView.ViewHolder {

    public final TextView mTextView;

    public FileHolder(View itemView, TextView tv) {
        super(itemView);
        mTextView = tv;
    }
}
Run Code Online (Sandbox Code Playgroud)

jim*_*251 37

编辑:现在修复了这个错误,如果你仍然得到相同的异常,请确保你只是从主线程更新你的适配器数据源并在它之后调用适当的适配器通知方法.

旧答案:这似乎是一个错误RecyclerView,它在这里这里报道.希望它将在下一个版本中修复.

  • 我正在使用编译'com.android.support:recyclerview-v7:23.0.0',但仍面临同样的问题. (19认同)
  • 仍面临问题...... :( (3认同)
  • 如果您尝试从后台线程更改列表内容,则会遇到同样的问题. (2认同)

Coc*_*ico 17

对我来说没问题.使用NotifyDataSetChanged();

public class MyFragment extends Fragment{

    private MyAdapter adapter;

    // Your code

    public void addArticle(){
        ArrayList<Article> list = new ArrayList<Article>();
        //Add one article in this list

        adapter.addArticleFirst(list); // or adapter.addArticleLast(list);
    }
}

public class ArticleAdapterRecycler extends RecyclerView.Adapter<ArticleAdapterRecycler.ViewHolder> {

    private ArrayList<Article> Articles = new ArrayList<Article>();
    private Context context;


    // Some functions from RecyclerView.Adapter<ArticleAdapterRecycler.ViewHolder>    

    // Add at the top of the list.

    public void addArticleFirst(ArrayList<Article> list) {
        Articles.addAll(0, list);
        notifyDataSetChanged();
    }

    // Add at the end of the list.

    public void addArticleLast(ArrayList<Article> list) {
        Articles.addAll(Articles.size(), list);
        notifyDataSetChanged();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你做两件事,notifyDataSetChanged也会动画项目1)在你的适配器上调用setHasStableIds(true)和2)覆盖getItemid从你的适配器为每一行返回一个唯一的长值,一旦你这样做,它将触发动画 (6认同)
  • 使用`notifyDataSetChanged()`时要注意的一点是,默认情况下它不会为更改的项设置动画,而`notifyItemChanged()`会. (2认同)

dra*_*eet 10

只是在数据发生变化时禁止RecyclerView的滚动.

像我的代码一样:

mRecyclerView.setOnTouchListener(
        new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (mIsRefreshing) {
                    return true;
                } else {
                    return false;
                }
            }
        }
);
Run Code Online (Sandbox Code Playgroud)

更多关于:http://drakeet.me/recyclerview-bug-indexoutofboundsexception-inconsistency-detected-invalid-item-position-solution

  • 什么是mIsRefreshing? (5认同)

Dor*_*lan 8

尽管在接受的答案中给出了关于此问题的几个有用的超链接,RecyclerView但是滚动时的这种行为是错误的.

如果您看到此异常,则很可能在RecyclerView"更改" 内容后忘记通知适配器.人们notifyDataSetChanged()只有在将项目添加到数据集后才会调用.但是,不仅在重新填充适配器后发生不一致,而且当您删除项目或清除数据集时,应通过向适配器通知此更改来刷新视图:

public void refillAdapter(Item item) {

    adapter.add(item);
    notifyDataSetChanged();

}

public void cleanUpAdapter() {

    adapter.clear();
    notifyDataSetChanged(); /* Important */

}
Run Code Online (Sandbox Code Playgroud)

在我的情况下,我试图清理适配器onStop(),并重新填充onStart().notifyDataSetChanged()使用后清洁适配器后我忘了打电话clear().然后,每当我将状态从更改onStop()onStart()并且RecyclerView在数据集重新加载时快速滚动时,我看到了这个异常.如果我在没有滚动的情况下等待重新加载的结束,则不会有异常,因为这次可以顺利恢复适配器.

简而言之,RecyclerView当视图改变时,它是不一致的.如果您尝试在处理数据集中的更改时滚动视图,您会看到java.lang.IndexOutOfBoundsException: Inconsistency detected.要消除此问题,应在更改数据集后立即通知适配器.


小智 7

如果您使用,这个问题就会出现在 recyclerview

adapter.setHasStableIds(true);
Run Code Online (Sandbox Code Playgroud)

如果你这样设置,删除它,并在适配器内更新你的数据集;
如果您仍然遇到问题,请在获得新数据后使所有视图无效,然后更新数据集。


Udi*_*ahi 5

问题绝对不是因为recyclerview滚动,而是与notifyDataSetChanged()有关.我有一个回收站视图,我不断更改数据,即添加和删除数据.我每次在列表中添加项目时都在调用notifyDataSetChanged(),但是每当删除项目或清除列表时都没有刷新适配器.

所以要修复:

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 2(offset:2).state:12 at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5456)
Run Code Online (Sandbox Code Playgroud)

我在list.clear()之后调用了adapter.notifyDataSetChanged(),无论它在何处需要.

if (!myList.isEmpty()) {
        myList.clear();
        myListAdapter.notifyDataSetChanged();
    }
Run Code Online (Sandbox Code Playgroud)

从那以后,我从未遇到异常.希望它也适用于其他人.:)