在Android中使用notifyItemRemoved或notifyDataSetChanged与RecyclerView

rev*_*ary 67 android android-listview notifydatasetchanged android-recyclerview

我正在创建一个使用RecyclerView显示的卡片列表,其中每张卡片都有一个按钮,可以从列表中删除该卡片.

当我使用notifyItemRemoved()删除RecyclerView中的卡时,它会删除项目和动画,但列表中的数据未正确更新.

如果不是这样,我切换到notifyDataSetChanged()然后列表中的项目被删除并正确更新,但然后卡片不动画.

有人有使用notifyItemRemoved()的经验,并知道为什么它的行为与notifyDataSetChanged不同?

以下是我正在使用的一些代码:

private List<DetectedIssue> issues = new ArrayList<DetectedIssue>();

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    // - get element from your dataset at this position
    // - replace the contents of the view with that element
    if(position >0){
        RiskViewHolder riskHolder = (RiskViewHolder)holder;
        final int index = position - 1;
        final DetectedIssue anIssue = issues.get(index);

        riskHolder.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    int index = issues.indexOf(anIssue);
                    issues.remove(anIssue);
                    notifyItemRemoved(index);

                    //notifyDataSetChanged();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

@Override
public int getItemCount() {
    return (issues.size()+1);
}
Run Code Online (Sandbox Code Playgroud)

Aks*_*jan 88

使用notifyItemRangeChanged(position,getItemCount()); 在notifyItemRemoved(position)之后;
您不需要使用索引,只需使用位置.见下面的代码.

private List<DetectedIssue> issues = new ArrayList<DetectedIssue>();

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    // - get element from your dataset at this position
    // - replace the contents of the view with that element
    if(position >0){
        RiskViewHolder riskHolder = (RiskViewHolder)holder;

        riskHolder.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    issues.remove(position);
                    notifyItemRemoved(position);
                    //this line below gives you the animation and also updates the
                    //list items after the deleted item
                    notifyItemRangeChanged(position, getItemCount());

                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

@Override
public int getItemCount() {
    return issues.size();
}
Run Code Online (Sandbox Code Playgroud)

  • 从文档中:“在此方法内部获取相关数据项时,您仅应使用position参数,而不应保留其副本。如果以后需要某个项目的位置(例如,在单击侦听器中),请使用RecyclerView。 ViewHolder.getAdapterPosition(),它将具有更新的适配器位置。” (2认同)
  • @YohanDahmani,notifyItemRemoved(位置); 如果您尝试使用最后一个项目,将无法正常工作。.IndexOutOfBoundException。 (2认同)

Gre*_*der 22

试着

public void removeItem(int position) {
    this.taskLists.remove(position);
    notifyItemRemoved(position);
    notifyItemRangeChanged(position, getItemCount() - position);
}
Run Code Online (Sandbox Code Playgroud)

和魅力一样工作.

  • 你能解释为什么你使用`getItemCount() - position`而不仅仅是`getItemCount()`? (5认同)

Tik*_*ikT 10

我的错误, notifyItemChanged(位置)很无奈,位置项可以删除,位置项+ 1很好,但是项目从位置+ 2开始,你会得到一个例外,请使用notifyItemRangeChanged(position,getItemCount) ()); notifyItemRemoved(position)之后;

像这样:

public void removeData(int position) {
    yourdatalist.remove(position);
    notifyItemRemoved(position);
    notifyItemRangeChanged(position,getItemCount());
}
Run Code Online (Sandbox Code Playgroud)

  • 请详细说明这样做会发生什么变化以及它将如何帮助解决问题。 (2认同)

rev*_*ary 1

正如 @pskink 所建议的,在我的情况下,它应该是 (index+1) ,可能是因为我为标头notifyItemRemoved(index+1)保留了顶部索引 ie 。position=0