RecyclerView 不会删除项目 - 尽管列表具有正确的项目编号

Posted

技术标签:

【中文标题】RecyclerView 不会删除项目 - 尽管列表具有正确的项目编号【英文标题】:RecyclerView doesn't delete items - although list has correct item number 【发布时间】:2021-07-17 08:16:21 【问题描述】:

我对 recyclerView(使用 GridLayoutManager)有一个奇怪的情况。 当我删除一个项目并使用 (notifyItemRemoved 和 notifyItemRangeChanged/notifyDataSetChanged) 刷新它时,它不会删除该项目,而是将其标记为删除(它有点灰显)。如果该项目不是最后一个,那么它有点被删除,但不是真的 - 它就在其他项目下并且不可见(如果我向这个项目添加额外的视图 - 你可以看到它在那里),但如果它是最后一个你可以看到它是灰色的。

这不是我第一次使用recyclerView,我之前也没有遇到过,但它是第一次使用GridLayoutManager,所以这可能是原因。

我已经调试过代码,刷新后重新创建recyclerView时,删除onBindViewHolder中的第5个后,可以清楚地看到List of items包含正确的项目(4)。

这里是当一个标记的图标被点击时的删除功能,它会得到一个 X 图标并出现对话框。

private class DeleteMessageDialog extends MessageDialog 
    List<Item> expenses;

    public DeleteMessageDialog(String message, List<Item> expenses) 
        super(DELETE_CATEGORY, WARNING, message, activity);
        this.expenses = expenses;
    

    @Override
    protected void okPressed() 
        DataHelper.getDataHelper(activity).removeItems(expenses);
        viewBuilder.refreshItems(DELETE_ITEM);
        dismiss();
    

刷新方法(我已经硬编码了 4 - 就像我之前使用 notifyDataSetChanged 一样快速而肮脏的解决方案)并根据 Phuc 评论更改了值:

public void refreshItems(Enums.Action action) 
    dataHelper.setListOfCategoryItems();
    List<Category> categoryItems = Utils.getCategoryItems(Utils.NO_PARENT_PREDICATE);
    categoryItemAdapter.updateData(categoryItems);
    MonthlyStatistics statistics = DataHelper.getDataHelper(activity).getMonthlyStatistics(Utils.getCurrentDate(PAY));
    statBuilder.populateStatistics(statistics.getStatistics().get(category));
    if (action == ADD_ITEM)
    
        activity.moveToMainPage();
        categoryItemAdapter.notifyDataSetChanged();
    
    if (action == DELETE_ITEM)
    
        categoryItemAdapter.notifyItemRemoved(4);
        categoryItemAdapter.notifyItemRangeChanged(4, 1);
    


updateData 方法

public void updateData(List<Category> categoryItems) 
    this.categoryItems.clear();
    this.categoryItems.addAll(categoryItems);
    this.parentsAndChildren.clear();
    this.parentsAndChildren.putAll(getChildrenAndParents(categoryItems));

在调试模式下,onBindViewHolder - 可以看到只剩下正确的 4 个项目

完成后就是这样的结果:

如果我删除第三项(不是最后一项),结果如下所示:

我已经搜索了所有互联网,但找不到解决方案,所以我希望在这里发布对您有所帮助。 欣赏所有答案。 谢谢。

编辑: 正如 Kamal Nayan 建议的那样,如果再次创建适配器并将其放入 recyclerView 确实有效,但我很确定有更好的解决方案,如果有人能找到它,我将不胜感激。

【问题讨论】:

尝试重新设置适配器? @KamalNayan 我一直在避免这个解决方案,但是是的,再次设置适配器是可行的,但我很确定这不是正确的做法,因为我们确实有所有的通知方法要做只是。不过感谢您的建议。 如果您想为此分享一个演示,我们可以彻底了解一下,因为这是一种奇怪的行为 @Zain 这几乎是一个带有屏幕截图的演示。屏幕截图的顺序正确。单击某个图标后,将出现删除消息。通过点击DELETE按钮,你看到的结果.. 【参考方案1】:

您误用了 notifyItemRemoved 和 notifyRangeChanged 的​​功能。在文档中:

notifyItemRemoved(int 位置)

with position 是项目被移除的位置。在您的情况下,您要删除第 5 项,因此您应该传递 4 而不是 5。

notifyRangeChanged(int positionStart, itemCount)

positionStart:已更改的第一项的位置 itemCount:已更改的项目数

如果你已经调用了notifyItemRemoved(),我认为这个方法是不必要的,但是你应该为 positionStart 传递 4,为 itemCount 传递 1,因为你只更改了第 5 个项目。

编辑:我想我在您的代码中发现了另一个问题。每当您删除一个项目时,您都会清除旧列表,然后将新列表传递给适配器。因为附加到适配器的先前列表已被删除并附加了一个新列表,所以您对 notifyItemRemoved() 的调用没有意义,因为在新列表中,没有任何变化。这会导致您面临意外的回收者视图行为。我建议的解决方案是您修改适配器中的列表,而不是每次删除时都创建新列表。例如在你的适配器中声明一个方法deleteItem(int position)

public void deleteItem(int position)
     yourList.remove(position);
     notifyItemRemoved(position);

【讨论】:

您对这两种方法的滥用是正确的,谢谢。我解决了这个问题,不幸的是它不能解决我的问题。 Kamal 建议的解决方案确实有效,但我很确定这不是正确的做法。 是的,不需要设置新的适配器。请看我编辑的答案 虽然我认为列表是同一个列表(当我从传递给状态列表的列表中添加项目时),我做了你的建议(从列表中明确删除项目而不添加其他列表中的项目),仍然得到相同的结果。 是的,对不起,你也许是对的。但至少我的方式会切断整个clear()addAll()。关于问题,很奇怪。是不是把GridLayout换成别的布局管理器(即:LinearLayoutManager),问题还存在吗? 是的,我现在已将其更改为线性。同样的问题。对我来说似乎是魔法。现在唯一可行的解​​决方案是重新加载适配器,我试图避免这种情况。

以上是关于RecyclerView 不会删除项目 - 尽管列表具有正确的项目编号的主要内容,如果未能解决你的问题,请参考以下文章

如何在recyclerview的gridLayoutManager中从cardview中删除右边距

RecyclerView 上的项目删除没有动画

如何修复 Recyclerview 项目删除显示错误

未从 RecyclerView 正确删除的项目

可过滤在 Recyclerview 中无法按预期工作

删除 RecyclerView android中项目之间的间距