Ich erstelle eine Liste von Karten, die mithilfe der RecyclerView-Karte angezeigt werden sollen, wobei jede Karte über eine Schaltfläche zum Entfernen dieser Karte aus der Liste verfügt.
Wenn ich notifyItemRemoved () verwende, um die Karte in der RecyclerView zu entfernen, wird das Element entfernt und animiert, aber die Daten in der Liste werden nicht korrekt aktualisiert.
Wenn ich stattdessen zu notifyDataSetChanged () wechsle, werden die Elemente in der Liste entfernt und korrekt aktualisiert. Die Karten werden jedoch nicht animiert.
Hat jemand Erfahrung mit notifyItemRemoved () und weiß, warum es sich anders verhält als notifyDataSetChanged?
Hier ist ein bisschen Code, den ich verwende:
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);
}
Wie @pskink vorschlug, sollte es in meinem Fall mit notifyItemRemoved(index+1)
(Index + 1) sein, wahrscheinlich, weil ich den oberen Index, d. H. position=0
, für einen Header reserviere.
Verwenden SienotifyItemRangeChanged (position, getItemCount ());after notifyItemRemoved (position);
Sie brauchen keinen Index zu verwenden, verwenden Sie einfach position. Siehe Code unten.
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();
}
Versucht
public void removeItem(int position) {
this.taskLists.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, getItemCount() - position);
}
und arbeiten wie ein Zauber.
mein Fehler, notifyItemChanged (position) ist hilflos, das Positionselement kann entfernt werden, und das Item von Position + 1 ist in Ordnung, aber die Elemente beginnen an Position + 2 und erhalten eine Ausnahme Bitte benutzen Sie notifyItemRangeChanged (position, getItemCount ()); after notifyItemRemoved (position);
so was:
public void removeData(int position) {
yourdatalist.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position,getItemCount());
}
Sie können getLayoutPosition()
aus dem RecyclerView.ViewHolder
verwenden.
getLayoutPosition()
gibt die genaue Position des Artikels im Layout und Code an
holder.removeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Position for remove
int modPosition= holder.getLayoutPosition();
//remove item from dataset
numbers.remove(modPosition);
//remove item from recycler view
notifyItemRemoved(modPosition);
}
});
In meinem Fall verwende ich Content Provider und einen Custom RecyclerView Adapter mit Cursor. In dieser Codezeile werden Sie benachrichtigt:
getContext().getContentResolver().notifyChange(uri, null);
In Ihrem RecyclerView-Adapter (Delete-Button) vorausgesetzt:
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");
}
Und in Ihrem Datenbankanbieter:
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;
**my solution looks like this**
this way is unnecessary to use the heavy method:
//notifyItemRangeChanged(xx,xx)
/**
*
* recyclerView的item中的某一个view,获取其最外层的viewParent,也就是item对应的layout在adapter中的position
*
* @param recyclerView
* @param view:can be the deep one inside the item,or the item itself .
* @return
*/
public static int getParentAdapterPosition(RecyclerView recyclerView, View view, int parentId) {
if (view.getId() == parentId)
return recyclerView.getChildAdapterPosition(view);
View viewGroup = (View) view.getParent();
if (viewGroup != null && viewGroup.getId() == parentId) {
return recyclerView.getChildAdapterPosition(viewGroup);
}
//recursion
return getParentAdapterPosition(recyclerView, viewGroup, parentId);
}
//wherever you set the clickListener .
holder.setOnClickListener(R.id.rLayout_device_item, deviceItemClickListener);
holder.setOnLongClickListener(R.id.rLayout_device_item, deviceItemLongClickListener);
@Override
public boolean onLongClick(View v) {
final int position = ViewUtils.getParentAdapterPosition(rVDevicesList, v, R.id.rLayout_device_item);
return true;
}