【问题标题】:Recyclerview binds index out of list size after adding items添加项目后,Recyclerview 将索引绑定到列表大小之外
【发布时间】:2017-09-18 16:28:54
【问题描述】:

我有一个带有 LinearLinearManager 的 RecyclerView。我的方法addItems()从网上下载数据,然后像这样一个接一个地添加10个项目:

itemIds.add(id);
listAdapter.notifyItemInserted(itemIds.size() - 1);

我在activity启动和用户滚动到(size - 3)时调用这个方法:

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        if (!pending && !loadingMoreItems &&
            listAdapter.getItemCount() - layoutManager.findLastVisibleItemPosition() <= 3) {
            loadingMoreItems = true;
            Log.d(LOG_TAG, "new data!");
            addItems();
        }
    }
});

当我启动应用程序并滚动到位置 7 时,会加载新数据。但是在添加了这些项目之后(新项目大小是 20,我检查了),我收到以下错误:

java.lang.IndexOutOfBoundsException:
Inconsistency detected. Invalid view holder adapter position
ViewHolder{9cff95d position=27 id=-1, oldPos=7, pLpos:5
scrap [attachedScrap] tmpDetached no parent}

因此,RecyclerView 想要将旧位置 7 的 ViewHolder 重用于新位置 27——当然,该位置不存在。

为了调试,我添加了一个扩展 LinearLayoutManager 的自定义类,以防止因 IndexOutOfBoundsException 而崩溃:

@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
    try {
        super.onLayoutChildren(recycler, state);
    } catch (IndexOutOfBoundsException e) {
        e.printStackTrace();
    }
}

然后我的列表完美运行 - 新项目顺利添加到列表中,甚至多次添加,因此它导致无限列表。 Logcat 中只有这个小堆栈跟踪。

我觉得只是使用 try/catch 来忽略这个 IndexOutOfBoundsException 是不对的,实际上在 catch 上什么也没做。有没有人知道如何解决这个奇怪的位置 27?

编辑:在测试了不同的item size后,我发现Recyclerview总是想在这个位置加载item:

&lt;position when reload request was started&gt; + 2 * &lt;reloaded item size&gt;

这当然总是超出列表的总大小。

【问题讨论】:

  • 你能分享你的适配器的基本版本吗?一开始你有10个项目,当你到达第7个项目时,你加载更多+10个项目,对吧?
  • 确实如此。适配器仅将列表大小作为 itemcount 返回,并且具有正常的创建和绑定功能,我认为这与此问题无关。

标签: android scroll android-recyclerview indexoutofboundsexception


【解决方案1】:

发生这种情况是因为您正在向列表中添加数据,同时您试图在通知适配器之前滚动 recyclerview。

所以当您在第 7 位之后加载数据时,请执行此操作

mData.add(yourdata);
mAdapter.notifyDataSetChanged();

如果您将继续添加数据并继续滚动它。它会给你“检测到不一致”。错误。因为适配器认为只有 7 个项目,当您滚动它时它已变为 10,而不会通知适配器。

【讨论】:

  • notifyDataSetChanged() 替换notifyItemInserted(...) 对我有用!不知道为什么,因为notifyItemInserted 实际上更具体,因此更好,但无论如何感谢您的正确回答! (PS:我认为不需要mAdapter.updateData(mData);,因为适配器和我的活动都引用了包含所有数据项的同一个 List 对象。)
【解决方案2】:

看来你得用这个方法listAdapter.notifyItemRangeInserted(startPosition, itemCount);

notifyItemInserted(position) 用于仅插入一项。如果要插入多个项目,则必须使用notifyItemRangeInserted(position, itemCount)

您是否会使用这种方法插入所有 10 个项目,而不是在循环中逐个添加并检查您是否遇到相同的异常?

【讨论】:

  • 感谢您的回答,但很遗憾,错误仍然存​​在。
【解决方案3】:

除了 Dinesh Bob 所说的之外,我认为您的代码没有任何问题。我只是要发布我如何在 RecyclerView 中实现分页:

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            int visibleItemCount=linearLayoutManager.getChildCount();
            int totalItemCount=linearLayoutManager.getItemCount();
            int firstVisibleItemPosition=linearLayoutManager.findFirstVisibleItemPosition();

            if(!isPageLoading && !isLastPage)
            {
                if((visibleItemCount + firstVisibleItemPosition)>=totalItemCount)
                {
                    offset+=limit;
                    loadMoreItems(offset);
                }
            }
        }
    });

loadMoreItems 继续进行 API 调用,然后将项目添加到适配器,如下所示:

public void addAllItems(List<Item> itemList)
{
    for(Item itemRow: itemList)
    {
        this.itemList.add(itemRow);
        notifyItemInserted(this.itemList.size() - 1);
    }
}

由于存在错误,在使用 ListView 时实现分页时需要捕获异常的块。但是recyclerview不需要它。

还会让您的代码试一试,看看它到底有什么问题。

【讨论】:

  • 谢谢,你的代码和我的几乎一样——我切换到了 firstVisibleItemPosition 而不是 lastVisible 并使用了 linearLayoutManager.getChildCount() 而不是 adapter.getChildCount(),但错误仍然存​​在。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-31
  • 2010-10-31
  • 2015-04-04
  • 1970-01-01
  • 1970-01-01
  • 2010-10-07
相关资源
最近更新 更多