Estoy creando una lista de tarjetas para mostrar el uso de la RecyclerView, donde cada tarjeta tiene un botón para quitar la tarjeta de la lista.

Cuando yo uso notifyItemRemoved() para quitar la tarjeta en el RecyclerView, se elimina el elemento y anima bien, pero los datos en la lista no se actualiza correctamente.

Si en lugar de eso, me cambie a la notifyDataSetChanged (), a continuación, los elementos de la lista se retiran y se actualiza correctamente, pero las cartas no se animan.

¿ Alguien tiene alguna experiencia en el uso de la notifyItemRemoved() y saber por qué se comporta de manera diferente que notifyDataSetChanged?

Aquí hay algunos peiece de código que estoy usando:

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);
}
  • trate de notifyItemRemoved(index+1)
  • Probablemente porque eres la eliminación de diferentes índices
  • El índice es correcta. Como ya he dicho todo funciona bien si uso notifyDataSetChanged() en su lugar…..
  • intenta notifyItemRemoved(index+1)?
  • Wow, mi problema exacto! Gracias por ahorrarme la molestia de simplificar mi código para hacer la pregunta clara.
  • Teniendo el mismo problema, índice+1 no funciona y el Rango de método no funcionó también.
  • liist.quitar(posición); notifyItemRemoved(posición); notifyItemRangeChanged(posición, getItemCount()); Para la eliminación de todos los tiempo de la parte superior del elemento.

8 Comentarios

  1. 84

    Uso notifyItemRangeChanged(posición, getItemCount()); después de notifyItemRemoved(posición);

    No es necesario utilizar el índice, sólo tiene que utilizar su posición. Véase el código de abajo.

    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();
    }
    • A partir de la documentación: «sólo Se debe utilizar el parámetro de posición, mientras que la adquisición de los datos relacionados con el artículo dentro de este método y no debe quedarse con una copia. Si usted necesita la posición de un elemento posterior (por ejemplo, en un clic, el que escucha), el uso de RecyclerView.ViewHolder.getAdapterPosition (), que tendrá la actualización de la posición del adaptador.»
    • Mahajan hilo Viejo lo siento, pero notifyItemRemoved(position); funciona bien solo (con animación). Lo notifyItemRangeChanged(position, getItemCount()); está haciendo ? Yo no puede ver la diferencia. Gracias
    • No debería ser getItemCount() – posición, como itemCount significa que el recuento de los elementos después de elemento eliminado?
    • sí, el segundo parámetro es el rango de los elementos modificados. el uso del número de elemento significa que cada elemento después de la posición está cambiando.
    • notifyItemRemoved(posición); no funcionará si usted está tratando en el último elemento..IndexOutOfBoundException usted va a conseguir.
    • Esta respuesta tiene sentido. Ambos notifyItemRemoved y notifyItemRangeChanged están haciendo la misma cosa. Por qué esta respuesta tiene tantos upvotes es un misterio.

  2. 21

    Intentado

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

    y el trabajo como un encanto.

    • Podría usted explicar por qué utilizar getItemCount() - position en lugar de sólo getItemCount()?
    • en realidad notifyItemRangeChanged(int posición, int itemCount) ción de la atc en la «posición» elementos han cambiado y de «posición» , «itemCount» elementos han cambiado, así que es conveniente que pasar sólo los elementos después de la «posición» en lugar de pasar lista de todos los elementos. O en lugar de pasar «getItemCount() – posición» podemos pasar getItemCount().
  3. 10

    mi error ,
    notifyItemChanged(posición) es impotente,el elemento de la posición puede ser eliminado ,y el elemento de la posición+1 es buena,pero los elementos de inicio de la posición+2,obtendrá una Excepción, por favor, utilice notifyItemRangeChanged(posición,getItemCount());
    después de notifyItemRemoved(posición);

    como este:

    public void removeData(int position) {
        yourdatalist.remove(position);
        notifyItemRemoved(position);
        notifyItemRangeChanged(position,getItemCount());
    }
    • por favor proporcione detalles sobre lo que va a cambiar por que hace esto y cómo va a ayudar a resolver el problema.
  4. 0

    Como @pskink sugirió que debía ser (index+1) en mi caso con notifyItemRemoved(index+1), probablemente porque me estoy reservando la parte superior índice, es decir, position=0 para un encabezado.

  5. 0

    Puede utilizar getLayoutPosition() de la RecyclerView.ViewHolder

    getLayoutPosition() proporciona la posición exacta del punto en el diseño y el código es

    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);
                }
            });
    • Usted debe utilizar getAdapterPosition como el documentación los estados, estás en riesgo de crear incoherencias.
  6. 0
    **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;
    }
  7. 0

    En mi caso yo uso el Proveedor de Contenidos, y es una Costumbre RecyclerView Adaptador con el Cursor. Esta línea de código es donde usted notifique a:

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

    Asumiendo En su recyclerView adaptador (Botón Eliminar):

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

    Y en la Base de datos del Proveedor de:

    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;
  8. -2

    Debe agregar quitar oyente en ViewHolder clase

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

Dejar respuesta

Please enter your comment!
Please enter your name here