Eliminar Datos Con Room

En este tutorial aprenderás a eliminar datos con Room con la anotación @Delete.

Al igual que @Insert y @Update es posible eliminar uno o varios registros de la base de datos y usar POJOs arbitrarios para especificar columnas particulares.


La Anotación @Delete

Para especificar que un método de un DAO será para eliminación márcalo con @Delete.

Sus parámetros deben ser objetos anotados con @Entity. Similar a las demás operaciones, Room flexibiliza la cantidad de filas que deseamos eliminar.

Ejemplo: Eliminar una, tres listas o una lista dinámica de listas de compras:

@Delete
void deleteShoppingList(ShoppingList shoppingList);

@Delete
void deleteShoppingLists(ShoppingList... shoppingLists);

@Delete
void deleteShoppingLists(List<ShoppingList> shoppingLists);

Si deseamos eliminar dependiendo de los valores de unas cuantas columnas, entonces podemos pasar un POJO que represente esta necesidad y lo asociamos con la propiedad entity.

Ejemplo: Crea una entidad llamada ShoppingListId para eliminar una lista de compras por su ID.

public class ShoppingListId {
    public String id;

    public ShoppingListId(String id) {
        this.id = id;
    }
}

Luego creamos un método en el DAO que reciba el objeto para que Room lo interprete como una entidad parcial:

@Delete(entity = ShoppingList.class)
void deleteShoppingList(ShoppingListId shoppingList);

Por otro lado, si quieres borrar todos los elementos de la tabla, debes acudir a la anotación @Query para ordenar la operación DELETE:

@Query("DELETE FROM shopping_list");
void deleteAllShoppingLists();

O si quieres eliminar por Id a través de parámetros bindeables, entonces:

@Query("DELETE FROM shopping_list WHERE id=:id")
void deleteShoppingList(String id);

Ejemplo Para Eliminar Datos Con Room

Para demostrar la eliminación añadiremos dos pequeños casos de uso a nuestra App de listas de compras como se ve en el siguiente prototipo:

Eliminar Datos Con Room

El primero es la eliminación individual desde el ítem de la lista y el segundo es la eliminación de todas las listas desde el overflow de la Toolbar.

A continuación vamos a ver los pasos principales para el desarrollo. Si deseas descargar el código para guiarte, usa el siguiente enlace:

Eliminar Lista De Compras Por Id

Esta característica nace del clic del usuario en un botón que existe en el ítem. Sabiendo esto, agreguémoslo al layout, procesemos el evento y propaguemos el evento hacia el ViewModel y el Repositorio.

Botón para eliminar lista de compras

1. Agregar Botón De Eliminar

Abre shopping_list_item.xml y posiciona al lado del botón de favorito, un ImageView que represente el ítem de acción para eliminar. Usa como como icono el vector asset llamado delete.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:padding="@dimen/normal_padding"
    android:layout_height="?listPreferredItemHeight">

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/favorite_button"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Lista de ejemplo" />

    <com.google.android.material.checkbox.MaterialCheckBox
        android:id="@+id/favorite_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:button="@drawable/sl_favorite_24"
        android:minWidth="0dp"
        android:minHeight="0dp"
        app:buttonTint="@color/favorite_color"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/delete_button"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/delete_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/ic_delete_24" />
</androidx.constraintlayout.widget.ConstraintLayout>

2. Procesar Clic En El Adaptador

De la misma forma que hicimos con el botón de favoritos, agrega un método para la eliminación:

interface ItemListener {
    void onClick(ShoppingListForList shoppingList);

    void onFavoriteIconClicked(ShoppingListForList shoppingList);

    void onDeleteIconClicked(ShoppingListForList shoppingList);
}

Luego asigna una escucha OnClickListener para que onDeleteIconClicked() sea disparado en la actividad principal:

public class ShoppingListViewHolder extends RecyclerView.ViewHolder {
    private final TextView mNameText;
    private final CheckBox mFavoriteButton;
    private final ImageView mDeleteButton;

    public ShoppingListViewHolder(@NonNull View itemView) {
        super(itemView);
        mNameText = itemView.findViewById(R.id.name);
        mFavoriteButton = itemView.findViewById(R.id.favorite_button);
        mDeleteButton = itemView.findViewById(R.id.delete_button);

        // Setear eventos
        mFavoriteButton.setOnClickListener(this::manageEvents);
        mDeleteButton.setOnClickListener(this::manageEvents);
        itemView.setOnClickListener(this::manageEvents);
    }

    private void manageEvents(View view) {
        if (mItemListener != null) {
            ShoppingListForList clickedItem = mShoppingLists.get(getAdapterPosition());

            // Manejar evento de click en Favorito
            if (view.getId() == R.id.favorite_button) {
                mItemListener.onFavoriteIconClicked(clickedItem);
                return;
            } else if (view.getId() == R.id.delete_button) {
                mItemListener.onDeleteIconClicked(clickedItem);
                return;
            }

            mItemListener.onClick(clickedItem);
        }
    }

    public void bind(ShoppingListForList item) {
        mNameText.setText(item.name);
        mFavoriteButton.setChecked(item.favorite);
    }
}

3. Propagar Acción Al ViewModel Y Repositorio

Ve a MainActivity y sobrescribe el método anteriormente creado. Este debe ejecutar un nuevo método de ShoppinListViewModel llamado deleteShoppingList(), el cuál recibe como parámetro la lista de compras:

// Asignar escucha de ítems
mAdapter.setItemListener(new ShoppingListAdapter.ItemListener() {
    @Override
    public void onClick(ShoppingListForList shoppingList) {
        editShoppingList(shoppingList);
    }

    @Override
    public void onFavoriteIconClicked(ShoppingListForList shoppingList) {
        mViewModel.markFavorite(shoppingList);
    }

    @Override
    public void onDeleteIconClicked(ShoppingListForList shoppingList) {
        mViewModel.deleteShoppingList(shoppingList);
    }
});

2. El método deleteShoppingList() mapeará el objeto entrante al POJO parcial que construimos. Asignando el id correspondiente:

public void deleteShoppingList(ShoppingListForList shoppingList) {
    ShoppingListId id = new ShoppingListId(shoppingList.id);
    mRepository.deleteShoppingList(id);
}

3. Ahora en el método equivalente del repositorio creamos un nuevo hilo y ejecutamos la eliminación desde el DAO.

public void deleteShoppingList(ShoppingListId id) {
    ShoppingListDatabase.dbExecutor.execute(
            () -> mShoppingListDao.deleteShoppingList(id)
    );
}

Al ejecutar el proyecto debes ver los ítems con su icono de eliminación. Y si pruebas clickear desaparecerán de la lista.

Eliminar Todas Las Listas De Compras

Esta acción es ejecutada desde un ítem de acción que se encuentra en el overflow de la Toolbar. Al igual que el caso anterior, agreguemos este botón, procesemos su clic y propaguemos las acciones hacia la capa de datos.

Action Button para eliminar todas las listas de compras

1. Añadir Action Button Para Eliminar

Crea un recurso de menú llamado main_menu.xml y agrega el ítem de eliminación:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/delete_all"
        android:title="@string/delete_all"
        app:showAsAction="never" />
</menu>

2. Procesar Evento De Action Button

Luego, ve a la actividad principal y añade los métodos onCreateOptionsMenu() para inflar el recurso anterior y onOptionsItemSelected() para detectar el evento de clic:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main_menu, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
    int itemId = item.getItemId();

    if (R.id.delete_all == itemId) {
        mViewModel.deleteAll();
        return true;
    }

    return super.onOptionsItemSelected(item);
}

3. Actualizar ViewModel Y Repositorio

Repetimos las tareas anteriores. Propagamos la acción de eliminación total desde el ViewModel con un nuevo método llamado deleteAll().

public void deleteAll() {
    mRepository.deleteAll();
}

El repositorio abrirá el hilo de trabajo y ejecutará el método de eliminación del DAO:

public void deleteAll() {
    ShoppingListDatabase.dbExecutor.execute(
            mShoppingListDao::deleteAllShoppingLists
    );
}

Y finalmente tendremos ambas características implementadas. Ejecuta y al presionar el ítem de eliminación de todas las listas verás:


Siguiente tutorial: Relaciones Uno A Uno Con Room

Únete Al Discord De Develou

Si tienes problemas con el código de este tutorial, preguntas, recomendaciones o solo deseas discutir sobre desarrollo Android conmigo y otros desarrolladores, únete a la comunidad de Discord de Develou y siéntete libre de participar como gustes. ¡Te espero!