Insertar Datos Con Room

En este tutorial verás cómo insertar datos con Room desde una actividad de creación de listas de compras.

Recuerda que puedes ver el alcance general de este ejemplo en la descripción de la App.

Al haber creado la base de datos de listas de compra, ahora agregaremos un RecyclerView para mejorar la vista de MainActivity.

Adicionalmente pondremos un FAB que inicie una nueva actividad de creación. El siguiente boceto muestra nuestro plan:

Insertar datos con Room

Puedes descargar el código completo desde el siguiente link:

Codifiquemos la solución.

1. Añadir RecyclerView Al Layout

Reemplazar el layout actual requiere las siguientes acciones:

  • Reemplazar ConstraintLayout raíz por CoordinatorLayout
  • Reemplazar TextView por RecyclerView
  • Añadir FAB en la parte inferior derecha
  • Añadir icono con símbolo ‘+’
  • Añadir soporte de vectores

Basado en ello, abre el layout activity_main.xml y pega el siguiente código:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:layout_height="match_parent"
    tools:context=".shoppinglists.MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/floating_action_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="16dp"
        app:srcCompat="@drawable/ic_add_24"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Para agregar el icono haz clic derecho en tu carpeta drawable, presiona New, luego Vector Asset. Seguido selecciona Clip Art en Asset Type, escribe «add» en el diálogo emergente y selecciona el icono que necesitamos.

Nómbralo ic_add_24 y confirma su inclusión.

Ahora abre el archivo build.gradle del módulo y pega la siguiente instrucción para habilitar el uso de vectores en el proyecto Android Studio:

defaultConfig {
        

        vectorDrawables.useSupportLibrary = true
        
    }

Sincroniza y tendremos completa nuestra interfaz para mostrar las listas de compras.


2. Crear Adaptador Del RecyclerView

El layout para el ítem de la lista es simple. Crea el archivo shopping_list_item.xml y recubre un TextView con un ConstraintLayout:

<?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_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Lista de ejemplo" />
</androidx.constraintlayout.widget.ConstraintLayout>

A continuación crea la clase ShoppingListAdapter.

La idea es inflar el layout del ítem. Agregar un método para actualizar los ítems y bindear el nombre de las listas de compra con el TextView existente.

Solución:

public class ShoppingListAdapter
        extends RecyclerView.Adapter<ShoppingListViewHolder> {

    private List<ShoppingList> mShoppingLists;

    @NonNull
    @Override
    public ShoppingListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return ShoppingListViewHolder.create(parent);
    }

    @Override
    public void onBindViewHolder(@NonNull ShoppingListViewHolder holder, int position) {
        ShoppingList item = mShoppingLists.get(position);
        holder.bind(item);
    }

    @Override
    public int getItemCount() {
        return mShoppingLists == null ? 0 : mShoppingLists.size();
    }

    public void setItems(List<ShoppingList> items) {
        mShoppingLists = items;
        notifyDataSetChanged();
    }

}

Crea también la clase ShoppingListViewHolder para procesar el inflado y el binding de cada ítem:

public class ShoppingListViewHolder extends RecyclerView.ViewHolder {
    private final TextView mNameText;

    public ShoppingListViewHolder(@NonNull View itemView) {
        super(itemView);
        mNameText = itemView.findViewById(R.id.name);
    }

    public void bind(ShoppingList item) {
        mNameText.setText(item.getName());
    }

    public static ShoppingListViewHolder create(ViewGroup parent) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.shopping_list_item, parent, false);
        return new ShoppingListViewHolder(v);
    }
}

3. Poblar RecyclerView Desde Room

¿Cómo ponemos el contenido de la base de datos en la lista?

  • Abre MainActivity
  • Obtén la instancia del RecyclerView
  • Crea una instancia del Adaptador y asígnala al recycler
  • Dirígete donde observamos el LiveData del ViewModel. Reemplaza ese código por la llamada del método setItems() del adaptador

Lo anterior reflejado en código sería así:

public class MainActivity extends AppCompatActivity {

    private ShoppingListViewModel mViewModel;
    private RecyclerView mList;
    private ShoppingListAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ViewModelProvider.AndroidViewModelFactory factory =
                ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication());

        mViewModel = new ViewModelProvider(this, factory)
                .get(ShoppingListViewModel.class);

        setupList();

        setupFab();
    }

    private void setupList() {
        mList = findViewById(R.id.list);
        mAdapter = new ShoppingListAdapter();
        mList.setAdapter(mAdapter);
        mViewModel.getShoppingLists().observe(this, mAdapter::setItems);
    }

    private void setupFab() {
        findViewById(R.id.floating_action_button)
                .setOnClickListener(view -> addNewShoppingList());
    }

    private void addNewShoppingList() {
        startActivity(new Intent(this, AddShoppingListActivity.class));
    }
}

Si ejecutas el proyecto en este punto deberías ver este resultado:

RecyclerView con Room

4. Añadir Actividad De Creación De Listas De Compras

Para la actividad de «Nueva lista» usaremos una plantilla Empty Activity. El nombre de la clase será AddShoppingListActivity.

El layout consta de un EditText y un botón de guardar. Abre activity_add_shopping_list.xml para satisfacer el diseño:

<?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:layout_height="match_parent"
    android:padding="@dimen/normal_padding"
    tools:context=".addshoppinglist.AddShoppingListActivity">

    <Button
        android:id="@+id/create_button"
        style="?attr/materialButtonOutlinedStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="@string/create_button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/name_layout" />

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/name_layout"
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/shopping_list_hint"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <com.google.android.material.textfield.TextInputEditText
            android:layout_width="match_parent"
            android:id="@+id/name_field"
            android:layout_height="wrap_content" />
    </com.google.android.material.textfield.TextInputLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

También debemos asegurarnos de retornar con el Up Button. Por lo que habilitamos su aparición con en onCreate():

public class AddShoppingListActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_shopping_list);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    

    @Override
    public boolean onSupportNavigateUp() {
        onBackPressed();
        return true;
    }
}

5. Guardar Lista Nueva En Base De Datos

Al presionar el botón de crear, debemos comunicárselo al ViewModel que es el encargado de insertar datos con Room con su método insert().

¿Cómo lo haces?

  • Obtén la instancia de ShoppingListViewModel en onCreate()
  • Obtén la instancia del boton de crear
  • Asigna un objeto OnClickListener al botón
  • Llama a insert() del view model en onClick()
  • Finaliza la actividad

Al completar las tareas anteriores tu actividad de creación se verá así:

public class AddShoppingListActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_shopping_list);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        ViewModelProvider.AndroidViewModelFactory factory
                = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication());
        ShoppingListViewModel vm = new ViewModelProvider(this, factory)
                .get(ShoppingListViewModel.class);

        setupCreateButton(vm);
    }

    private void setupCreateButton(ShoppingListViewModel vm) {
        findViewById(R.id.create_button).setOnClickListener(
                view -> {
                    // Obtener valor del campo de texto
                    EditText nameField =  findViewById(R.id.name_field);
                    String name = nameField.getText().toString();

                    // Ignorar acción si hay 0 caracteres
                    if (name.isEmpty()) {
                        return;
                    }

                    // Crear entidad y guardarla
                    String id = UUID.randomUUID().toString();
                    ShoppingList shoppingList = new ShoppingList(id, name);
                    vm.insert(shoppingList);

                    // Ir a la lista
                    finish();
                });
    }

    @Override
    public boolean onSupportNavigateUp() {
        onBackPressed();
        return true;
    }
}

No olvides iniciar esta actividad al presionar el FAB de la lista:

    private void setupFab() {
        findViewById(R.id.floating_action_button)
                .setOnClickListener(view -> addNewShoppingList());
    }

    private void addNewShoppingList() {
        startActivity(new Intent(this, AddShoppingListActivity.class));
    }

Ejecuta el proyecto y comprueba la inserción de listas.

Nota: Aunque en este ejemplo estamos usando un solo ViewModel, normalmente debes crear uno por cada controlador de vista.


6. Insertar Una Lista De Entities

Room tiene la capacidad de insertar múltiples entidades si pasamos una lista como parámetro.

Para ver su funcionamiento agreguemos a ShoppingListDao el siguiente método:

@Insert(onConflict = OnConflictStrategy.IGNORE)
void insertShoppingLists(List<ShoppingList> lists);

Ahora desde ShoppingListDatabase creamos una lista de 5 elementos para reemplazar la prepoblación que hacíamos antes de forma individual:

    // Prepoblar base de datos con callback
    private static final RoomDatabase.Callback mRoomCallback = new Callback() {
        @Override
        public void onCreate(@NonNull SupportSQLiteDatabase db) {
            super.onCreate(db);

            dbExecutor.execute(() -> {
                ShoppingListDao dao = INSTANCE.shoppingListDao();

                List<ShoppingList> lists = new ArrayList<>();
                for (int i = 0; i < 5; i++) {
                    String id = UUID.randomUUID().toString();
                    lists.add(new ShoppingList(id, "Lista " + (i+1)));
                }

                dao.insertShoppingLists(lists);
            });
        }
    };

De esta forma podremos hacer en una misma transacción un bulk de inserciones de listas de compras.


Siguiente tutorial: Consultar Datos Con Room [en proceso…]

Ú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!