在Android中使用notifyItemRemoved或notifyDataSetChanged与RecyclerView
我正在使用RecyclerView创建一个要显示的卡片列表,其中每张卡片都有一个从列表中删除该卡片的按钮 当我使用notifyItemRemoved()删除RecyclerView中的卡时,它会删除该项并设置动画,但列表中的数据没有正确更新 如果不是这样,而是切换到notifyDataSetChanged(),则列表中的项目将被删除并正确更新,但卡不会动画 是否有人有使用notifyItemRemoved()的经验,并且知道为什么它的行为与notifyDataSetChanged不同 下面是我正在使用的一些代码:在Android中使用notifyItemRemoved或notifyDataSetChanged与RecyclerView,android,android-listview,android-recyclerview,notifydatasetchanged,Android,Android Listview,Android Recyclerview,Notifydatasetchanged,我正在使用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);
}
private List issues=new ArrayList();
@凌驾
BindViewHolder上的公共无效(RecyclerView.ViewHolder,int位置){
//-在此位置从数据集中获取元素
//-用该元素替换视图的内容
如果(位置>0){
RiskViewHolder riskHolder=(RiskViewHolder)持有人;
最终综合指数=位置-1;
最终检测到的问题anIssue=issues.get(索引);
riskHolder.button.setOnClickListener(新视图.OnClickListener(){
@凌驾
公共void onClick(视图v){
试一试{
int index=issues.indexOf(anIssue);
问题。移除(anIssue);
删除的项目(索引);
//notifyDataSetChanged();
}捕获(SQLE异常){
e、 printStackTrace();
}
}
});
}
}
@凌驾
public int getItemCount(){
返回(issues.size()+1);
}
正如@pskink建议的那样,在我使用notifyItemRemoved(index+1)
的情况下,应该是(index+1),可能是因为我为标题保留了顶部索引,即position=0
。您应该在ViewHolder类中添加remove listener
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onCancel(getAdapterPosition());
}
});
private void onCancel(int position) {
if (position >= issues.size())
return;
issues.remove(position);
notifyItemRemoved(position);
}
使用notifyItemRangeChanged(位置,getItemCount())删除后(位置)您不需要使用索引,只需使用位置。请参阅下面的代码
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();
}
private List issues=new ArrayList();
@凌驾
BindViewHolder上的公共无效(RecyclerView.ViewHolder,int位置){
//-在此位置从数据集中获取元素
//-用该元素替换视图的内容
如果(位置>0){
RiskViewHolder riskHolder=(RiskViewHolder)持有人;
riskHolder.button.setOnClickListener(新视图.OnClickListener(){
@凌驾
公共void onClick(视图v){
试一试{
问题。移除(位置);
已移除(位置)的项目;
//下面这一行为您提供动画,并更新
//在删除的项目之后列出项目
notifyItemRangeChanged(位置,getItemCount());
}捕获(SQLE异常){
e、 printStackTrace();
}
}
});
}
}
@凌驾
public int getItemCount(){
返回问题。大小();
}
我的错误,
notifyItemChanged(position)无法使用,position的项目可以删除,position+1的项目可以,但是项目从position+2开始,您会得到一个异常,请使用notifyItemRangeChanged(position,getItemCount())强>
移除后(位置)强>
像这样:
public void removeData(int position) {
yourdatalist.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position,getItemCount());
}
尝试
您可以使用
RecyclerView.ViewHolder中的getAdapterPosition()
getLayoutPosition()
提供项目在布局中的确切位置,代码为
holder.removeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Position for remove
int modPosition= holder.getAdapterPosition();
//remove item from dataset
numbers.remove(modPosition);
//remove item from recycler view
if(numbers.isEmpty())
notifyDataSetChanged ()
else
notifyItemRemoved(modPosition);
}
});
在我的例子中,我使用内容提供者和带有游标的自定义RecyclerView适配器。这行代码是您通知的地方:
getContext().getContentResolver().notifyChange(uri, null);
假设在您的recyclerView适配器中(删除按钮):
在数据库提供程序中:
case TODO_ID:
selection = DatabaseContract.ToDoEntry._ID + "=?";
selectionArgs = new String[] {String.valueOf(ContentUris.parseId(uri))};
rowsDeleted = database.delete(DatabaseContract.ToDoEntry.TODO_TABLE_NAME, selection, selectionArgs);
if (rowsDeleted != 0){
getContext().getContentResolver().notifyChange(uri, null);
}
return rowsDeleted;
尝试notifyItemRemoved(索引+1)索引正确。正如我所说的,如果我改用notifyDataSetChanged(),一切都会正常工作……您是否尝试过notifyItemRemoved(索引+1)?哇,我的问题就在这里!谢谢你帮我省去了简化代码的麻烦,把问题弄清楚了。liist.remove(position);已移除(位置)的项目;notifyItemRangeChanged(位置,getItemCount());用于删除每次最上面的元素。请提供详细信息,说明执行此操作将改变什么,以及如何帮助解决此问题。此操作有效。行对象的位置也将被更新。从文档中可以看到:“在获取此方法中的相关数据项时,您应该只使用position参数,而不应该保留它的副本。如果以后需要项目的位置(例如,在单击侦听器中),请使用RecyclerView.ViewHolder.getAdapterPosition()将更新适配器位置。“@Akshay Mahajan旧线程抱歉,但notifyItemRemoved(位置)代码>单独工作(使用动画)效果很好。notifyItemRangeChanged(位置,getItemCount())代码>正在做什么?我看不出有什么区别。谢谢,不应该是getItemCount()-position,因为itemCount表示删除项目后的项目数?是的,第二个参数是更改项目的范围。使用项目计数表示位置后的每个项目都在更改。@YohanDahmani,notifyItemRemoved(位置);如果您正在尝试最后一项,则将不起作用。您将获得IndexOutOfBoundException。您应该使用getAdapterPosition作为状态,您有可能创建不一致。使用此notifyItemRemoved(last pos)删除数组列表的最后一个元素时出错。是否有相同的解决方案?是否可以检查此问题?if(numbers.isEmpty())notifyDataSetChanged()else notifyItemRemoved(modPosition);您能解释一下为什么使用getItemCount()-position
而不仅仅是getitemcont吗
getContext().getContentResolver().notifyChange(uri, null);
Uri currentUri = ContentUris.withAppendedId(DatabaseContract.ToDoEntry.CONTENT_URI_TODO, id);
int rowsDeleted = mContext.getContentResolver().delete(currentUri, null, null);
if (rowsDeleted == 0) {
Log.d(TAG, "onClick: Delete failed");
} else {
Log.d(TAG, "onClick: Delete Successful");
}
case TODO_ID:
selection = DatabaseContract.ToDoEntry._ID + "=?";
selectionArgs = new String[] {String.valueOf(ContentUris.parseId(uri))};
rowsDeleted = database.delete(DatabaseContract.ToDoEntry.TODO_TABLE_NAME, selection, selectionArgs);
if (rowsDeleted != 0){
getContext().getContentResolver().notifyChange(uri, null);
}
return rowsDeleted;