web-dev-qa-db-fra.com

utilisation de notifyItemRemoved ou notifyDataSetChanged avec RecyclerView dans Android

Je crée une liste de cartes à afficher à l'aide de RecyclerView, chaque carte ayant un bouton permettant de supprimer cette carte de la liste.

Lorsque j'utilise notifyItemRemoved () pour retirer la carte du RecyclerView, l’élément est supprimé et l’animation est correcte, mais les données de la liste ne sont pas mises à jour correctement. 

Si au lieu de cela, je passe à notifyDataSetChanged () , alors les éléments de la liste sont supprimés et mis à jour correctement, mais les cartes ne s'animent pas.

Quelqu'un at-il une expérience dans l’utilisation de notifyItemRemoved () et sait-il pourquoi il se comporte différemment de notifyDataSetChanged?

Voici quelques morceaux de code que j'utilise:

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);
}
59
revolutionary

Comme @pskink l'a suggéré, cela devait être (index + 1) dans mon cas avec notifyItemRemoved(index+1), probablement parce que je réserve l'index supérieur, à savoir position=0, pour un en-tête.

0
revolutionary

UtiliseznotifyItemRangeChanged (position, getItemCount ());after notifyItemRemoved (position);
Vous n'avez pas besoin d'utiliser l'index, utilisez simplement la position. Voir le code ci-dessous.

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();
}
78
Akshay Mahajan

A tenté

public void removeItem(int position) {
    this.taskLists.remove(position);
    notifyItemRemoved(position);
    notifyItemRangeChanged(position, getItemCount() - position);
}

et travailler comme un charme.

17
Grender

mon erreur, notifyItemChanged (position) est impuissant, l'élément de position peut être supprimé, et l'élément de position + 1 est correct, mais les éléments commencent à la position + 2, vous obtiendrez une exception, veuillez utiliser notifyItemRangeChanged (position, getItemCount ()); après notifyItemRemoved (position);

comme ça:

public void removeData(int position) {
    yourdatalist.remove(position);
    notifyItemRemoved(position);
    notifyItemRangeChanged(position,getItemCount());
}
9
TikT

Vous pouvez utiliser getLayoutPosition() à partir du RecyclerView.ViewHolder

getLayoutPosition() fournit la position exacte de l'élément dans la mise en page et le code est

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);
            }
        });
0
sree

Dans mon cas, j'utilise un fournisseur de contenu et un adaptateur RecyclerView personnalisé avec curseur. Cette ligne de code est l'endroit où vous notifiez:

getContext().getContentResolver().notifyChange(uri, null);

En supposant que dans votre adaptateur recyclerView (bouton Supprimer):

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");
}

Et dans votre fournisseur de base de données:

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;
0
MohammadL
**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;
}
0
dong sheng