Android

Android y SQLite: agenda | Ejemplo de app con RecyclerView

Vamos a practicar un poco más con SQLite y Android con otro ejercicio práctico: la creación de una agenda.

Se pretende realizar una aplicación de una agenda en donde se escriba un identificador, el número de teléfono y el nombre de una persona.

Viéndolo desde el punto de vista de diseño de bases de datos o experiencia de usuario el ejercicio no estará muy bien; pero servirá mucho para practicar porque veremos cómo:

  1. Insertar un registro en SQLite
  2. Obtener un registro por ID
  3. Comprobar si un registro ya existe
  4. Listar los registros existentes

Si quieres ver un ejemplo en donde también se Edita y Elimina mira el CRUD de SQLite con Android en donde trabajamos con mascotas. También te invito a que pruebes la app para el control de gastos que publiqué hace algunos días.

Repositorio en GitHub

A través del post mostraré el código más importante, pero si quieres ver el código completo mira el repositorio en GitHub.

Más ejercicios

Anteriormente publiqué otros ejercicios con Android:

Otras cosas que he escrito sobre Android las puedes encontrar aquí. Ahora sí, comencemos.

Diseño de actividad principal

La actividad principal tiene 3 botones: uno para insertar un registro, otro para consultar por identificador y finalmente uno para listar todos los registros existentes.

Diseño de actividad principal de Agenda en Android

El código del layout es el siguiente:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btnRegistrar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:text="@string/registrar"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btnConsultar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:text="@string/consultar"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btnRegistrar" />

    <Button
        android:id="@+id/btnListar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:text="@string/listar"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btnConsultar" />

</android.support.constraint.ConstraintLayout>

Para el funcionamiento simplemente instanciamos los botones, agregamos listeners y en cada uno de ellos llamamos a startActivity pasándole un Intent que lleva a otra actividad.

package me.parzibyte.agenda;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

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

        Button btnRegistrar = findViewById(R.id.btnRegistrar),
                btnConsultar = findViewById(R.id.btnConsultar),
                btnListar = findViewById(R.id.btnListar);

        btnRegistrar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, ActivityRegistrar.class);
                startActivity(intent);
            }
        });
        btnConsultar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, ActivityConsultar.class);
                startActivity(intent);
            }
        });
        btnListar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, ActivityListar.class);
                startActivity(intent);
            }
        });
    }
}

Por el momento, las clases de destino no existen; vamos a crearlas más tarde. Fíjate en que cada llamada a findViewById tiene que ver con el id que tiene cada botón.

Utilerías

Antes de continuar veremos un archivo de “utilerías” al que yo más bien llamaría Constantes (las típicas constantes estáticas públicas de Java) en donde tenemos la definición de la tabla, los nombres de los campos y esas cosas.

package me.parzibyte.agenda;

public class Utilerias {
    public static final String TABLA_PERSONA = "Persona";
    public static final String NOMBRE_BD = "agenda";
    public static final String CAMPO_ID = "id";
    public static final String CAMPO_NOMBRE = "nombre";
    public static final String CAMPO_TELEFONO = "telefono";
    public static final String CREAR_TABLA_PERSONA = "create table "
            + TABLA_PERSONA
            + " (" + CAMPO_ID + " INTEGER, "
            + CAMPO_NOMBRE + " TEXT, " + CAMPO_TELEFONO + " TEXT)";
}

En el archivo tenemos la creación de tablas y los nombres de los campos de cada tabla.

La clase Persona

Para hacer las cosas al modo de Java vamos a crear una clase Persona que vamos a estar instanciando para pasarla a través de los métodos en donde los datos se guardan.

No es obligatorio, pero es un buen paradigma. La clase queda así:

package me.parzibyte.agenda.modelos;

public class Persona {
    private String nombre, telefono;
    private int id;

    public Persona(String nombre, String telefono, int id) {
        this.nombre = nombre;
        this.telefono = telefono;
        this.id = id;
    }

    public Persona(String nombre, String telefono) {
        this.nombre = nombre;
        this.telefono = telefono;
    }

    public Persona() {
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public String getTelefono() {
        return telefono;
    }

    public void setTelefono(String telefono) {
        this.telefono = telefono;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

Tiene sus getters y setters; los setters no están siendo utilizados pero los getters si. Eso es más que nada por el encapsulamiento, cosa que no tiene lugar en este post.

Helper de SQLite

Debemos crear una clase que extienda de SQLiteOpenHelper. Vamos a sobrescribir el constructor y los métodos onCreate y onUpgrade.

package me.parzibyte.agenda;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class ConexionSQLiteHelper extends SQLiteOpenHelper {


    public ConexionSQLiteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(Utilerias.CREAR_TABLA_PERSONA);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + Utilerias.TABLA_PERSONA);
        onCreate(db);
    }
}

El método onCreate es llamado cuando la base de datos es creada por primera vez. Aquí se deberían crear las tablas y llenar los datos iniciales si son necesarios. Lo único que hacemos es crear la tabla.

El método onUpgrade es cuando entregamos una nueva versión de la base de datos; en ese método modificamos las tablas o datos para realizar la actualización para los usuarios que ya tenían la base de datos instalada. Lo único que hacemos es eliminar la BD y volverla a crear.

Insertar persona en Agenda

Ahora veamos el primer paso de este crud: hacer un registro. Tenemos el layout en donde solicitamos:

  1. Identificador de persona
  2. Número de teléfono
  3. Nombre
Registrar contacto en Agenda de Android – SQLite

Son 3 EditText y un Button. El layout queda así:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
    tools:context=".ActivityRegistrar">

    <EditText
        android:id="@+id/etIdentificador"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:ems="10"
        android:hint="@string/identificador"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/etNombre"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:ems="10"
        android:hint="@string/nombre"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/etIdentificador" />

    <EditText
        android:id="@+id/etTelefono"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:ems="10"
        android:hint="@string/tel_fono"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/etNombre" />

    <Button
        android:id="@+id/btnRegistrar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:hint="@string/guardar"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/etTelefono" />
</android.support.constraint.ConstraintLayout>

Al presionar el botón se debe generar un registro. Para hacerlo usamos ContentValues, le ponemos los valores obtenidos de los EditText; creamos una nueva instancia de la base de datos y hacemos el registro de la persona.

package me.parzibyte.agenda;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class ActivityRegistrar extends AppCompatActivity {

    private boolean existe(String id) {
        ConexionSQLiteHelper conexion = new ConexionSQLiteHelper(ActivityRegistrar.this, Utilerias.NOMBRE_BD, null, 1);
        SQLiteDatabase bd = conexion.getReadableDatabase();
        String[] parametros = {id};
        String[] campos = {Utilerias.CAMPO_NOMBRE};
        Cursor cursor = bd.query(Utilerias.TABLA_PERSONA,
                campos,
                Utilerias.CAMPO_ID + "=?",
                parametros,
                null,
                null,
                null);
        return cursor.moveToFirst();
    }

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

        final EditText etIdentificador = findViewById(R.id.etIdentificador),
                etNombre = findViewById(R.id.etNombre),
                etTelefono = findViewById(R.id.etTelefono);

        Button btnRegistrar = findViewById(R.id.btnRegistrar);
        btnRegistrar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String identificador = etIdentificador.getText().toString(),
                        nombre = etNombre.getText().toString(),
                        telefono = etTelefono.getText().toString();
                if (existe(identificador)) {
                    Toast.makeText(ActivityRegistrar.this, "Identificador existente", Toast.LENGTH_SHORT).show();
                    return;
                }

                if (identificador.isEmpty() || nombre.isEmpty() || telefono.isEmpty()) return;
                ContentValues contentValues = new ContentValues();
                contentValues.put(Utilerias.CAMPO_ID, identificador);
                contentValues.put(Utilerias.CAMPO_NOMBRE, nombre);
                contentValues.put(Utilerias.CAMPO_TELEFONO, telefono);

                ConexionSQLiteHelper conexion = new ConexionSQLiteHelper(ActivityRegistrar.this,
                        Utilerias.NOMBRE_BD, null, 1);
                SQLiteDatabase bd = conexion.getWritableDatabase();
                long respuesta = bd.insert(Utilerias.TABLA_PERSONA, null, contentValues);
                Toast.makeText(ActivityRegistrar.this, "Registro #" + respuesta, Toast.LENGTH_SHORT).show();
                bd.close();
            }
        });
    }
}

Dentro del código también existe el método existe, el cual recibe un identificador como cadena, hace una consulta y nos indica si un registro con determinado identificador ya está registrado.

Hacemos una simple validación con .isEmpty() para ver si los datos están vacíos y también llamamos al método existe para evitar registros con ids duplicados.; después obtenemos la base de datos en modo escritura y llamamos al método insert, el cual devuelve un tipo de dato long indicando el row id del nuevo registro.

Mostramos el número de registro en un Toast y con eso queda.

Consultar persona en Agenda

La interfaz para consultar pide el identificador y rellena los EditText con los datos traídos de la base de datos.

Si los datos existen, se rellenan los EditText. Si no, se muestra un Toast indicando que no existe.

Búsqueda de contacto en Agenda de Android – SQLite

El layout queda así:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
    tools:context=".ActivityConsultar">

    <EditText
        android:id="@+id/etIdBusqueda"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:ems="10"
        android:hint="@string/id"
        android:inputType="numberSigned"
        app:layout_constraintEnd_toStartOf="@+id/btnBuscar"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btnBuscar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:text="@string/buscar"
        app:layout_constraintBaseline_toBaselineOf="@+id/etIdBusqueda"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/etIdBusqueda" />

    <EditText
        android:id="@+id/etMostrarNombre"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:ems="10"
        android:hint="@string/nombre"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/etIdBusqueda" />

    <EditText
        android:id="@+id/etMostrarTelefono"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:ems="10"
        android:hint="@string/tel_fono"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/etMostrarNombre" />
</android.support.constraint.ConstraintLayout>

Definimos lo que se ve en la imagen. El código Java para escuchar el click del botón, buscar el registro y poner los datos en el EditText queda así:

package me.parzibyte.agenda;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class ActivityConsultar extends AppCompatActivity {

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

        final EditText etIdBusqueda = findViewById(R.id.etIdBusqueda),
                etMostrarNombre = findViewById(R.id.etMostrarNombre),
                etMostrarTelefono = findViewById(R.id.etMostrarTelefono);

        Button btnBuscar = findViewById(R.id.btnBuscar);
        btnBuscar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String idBusqueda = etIdBusqueda.getText().toString();
                if (idBusqueda.isEmpty()) return;
                ConexionSQLiteHelper conexion = new ConexionSQLiteHelper(ActivityConsultar.this, Utilerias.NOMBRE_BD, null, 1);
                SQLiteDatabase bd = conexion.getReadableDatabase();
                String[] parametros = {idBusqueda};
                String[] campos = {Utilerias.CAMPO_NOMBRE, Utilerias.CAMPO_TELEFONO};
                Cursor cursor = bd.query(Utilerias.TABLA_PERSONA,
                        campos,
                        Utilerias.CAMPO_ID + "=?",
                        parametros,
                        null,
                        null,
                        null);
                if (!cursor.moveToFirst()) {
                    Toast.makeText(ActivityConsultar.this, "ID Inexistente", Toast.LENGTH_SHORT).show();
                    etMostrarNombre.setText("");
                    etMostrarTelefono.setText("");
                    bd.close();
                    return;
                }

                etMostrarNombre.setText(cursor.getString(cursor.getColumnIndex(Utilerias.CAMPO_NOMBRE)));
                etMostrarTelefono.setText(cursor.getString(cursor.getColumnIndex(Utilerias.CAMPO_TELEFONO)));

            }
        });
    }
}

Nuevamente usamos a Toast para indicar los mensajes. Ahora llamamos al método query que devuelve un cursor (como en la función para comprobar si el identificador ya existía) y buscamos los datos en donde el id sea igual al proporcionado.

Por cierto, ahora no queremos la base de datos en modo escritura; solo lectura.

En caso de que haya datos obtenemos a los mismos con cursor.getString, pasándole el índice de la columna que, para no equivocarnos, obtenemos con getColumnIndex.

Listar personas de Agenda

Para terminar el ejercicio veamos la forma de listar los datos de la agenda. Esto es un poco más complejo porque involucra un RecyclerView y un adaptador para el mismo. además del diseño de un layout para cada fila y algunos otros métodos.

Listar contactos existentes en Agenda de Android – SQLite

La lista debe mostrar el id, el número de teléfono y el nombre de la persona.

Adaptador del RecyclerView

Para empezar definimos el layout que tendrá el RecyclerView:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
    tools:context=".ActivityListar">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerViewPersonas"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginStart="0dp"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="0dp"
        android:layout_marginEnd="0dp"
        android:layout_marginRight="0dp"
        android:layout_marginBottom="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

El RecyclerView mostrará filas. La fila individual queda así:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/selectableItemBackground"
    android:clickable="true"
    android:focusable="true"
    android:padding="5dp">

    <TextView
        android:id="@+id/tvFilaNombre"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:text="Nombre"
        android:textColor="@color/colorPrimaryDark"
        android:textSize="18sp"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tvFilaEdad"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:text="Teléfono"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tvFilaNombre" />

    <TextView
        android:id="@+id/tvFilaIdentificador"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:text="TextView"
        android:textColor="@color/colorAccent"
        app:layout_constraintBaseline_toBaselineOf="@+id/tvFilaNombre"
        app:layout_constraintStart_toEndOf="@+id/tvFilaNombre"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

El adaptador que se encarga de poner los datos de la persona en la fila es el siguiente:

package me.parzibyte.agenda;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

import me.parzibyte.agenda.modelos.Persona;

public class AdaptadorPersonas extends RecyclerView.Adapter<AdaptadorPersonas.MyViewHolder> {
    private List<Persona> listaDePersonas;

    public List<Persona> getListaDePersonas() {
        return listaDePersonas;
    }

    public void setListaDePersonas(List<Persona> listaDePersonas) {
        this.listaDePersonas = listaDePersonas;
    }

    public AdaptadorPersonas(List<Persona> listaDePersonas) {
        this.listaDePersonas = listaDePersonas;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View filaPersona = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fila_persona, viewGroup, false);
        return new MyViewHolder(filaPersona);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, int i) {
// Obtener la persona de nuestra lista gracias al índice i
        Persona persona = listaDePersonas.get(i);

        // Obtener los datos de la lista
        String nombre = persona.getNombre();
        String telefono = persona.getTelefono();
        String identificador = String.valueOf(persona.getId());
        // Y poner a los TextView los datos con setText
        myViewHolder.tvNombre.setText(nombre);
        myViewHolder.tvEdad.setText(telefono);
        myViewHolder.tvIdentificador.setText(identificador);
    }

    @Override
    public int getItemCount() {
        return listaDePersonas.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        TextView tvNombre, tvEdad, tvIdentificador;

        MyViewHolder(View itemView) {
            super(itemView);
            this.tvNombre = itemView.findViewById(R.id.tvFilaNombre);
            this.tvEdad = itemView.findViewById(R.id.tvFilaEdad);
            this.tvIdentificador = itemView.findViewById(R.id.tvFilaIdentificador);
        }
    }
}

De modo general está obteniendo la fila y poniendo cada valor en su posición de la fila; es decir, cada valor en un EditText. Ese método será llamado por cada fila del RecyclerView.

También definimos el constructor en donde vamos a estar trabajando con una lista (List) de tipo Persona para saber a cuál persona dibujar en determino lugar.

Actividad que consulta datos y los pone en RecyclerView

Finalmente la actividad que obtiene la lista de personas y la pone al adaptador para el RecyclerView es la siguiente:

package me.parzibyte.agenda;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import java.util.ArrayList;

import me.parzibyte.agenda.modelos.Persona;

public class ActivityListar extends AppCompatActivity {

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

        RecyclerView recyclerView = findViewById(R.id.recyclerViewPersonas);

        ConexionSQLiteHelper conexion = new ConexionSQLiteHelper(ActivityListar.this, Utilerias.NOMBRE_BD, null, 1);
        SQLiteDatabase bd = conexion.getReadableDatabase();
        String[] campos = {Utilerias.CAMPO_NOMBRE, Utilerias.CAMPO_TELEFONO, Utilerias.CAMPO_ID};
        Cursor cursor = bd.query(Utilerias.TABLA_PERSONA,
                campos,
                null,
                null,
                null,
                null,
                null);
        if (!cursor.moveToFirst()) {
            cursor.close();
            bd.close();
            return;
        }

        ArrayList<Persona> personas = new ArrayList<>();


        do {
            String nombre = cursor.getString(cursor.getColumnIndex(Utilerias.CAMPO_NOMBRE));
            String telefono = cursor.getString(cursor.getColumnIndex(Utilerias.CAMPO_TELEFONO));
            int id = cursor.getInt(cursor.getColumnIndex(Utilerias.CAMPO_ID));
            Persona persona = new Persona(nombre, telefono, id);
            personas.add(persona);
        } while (cursor.moveToNext());

        // Fin del ciclo. Cerramos cursor y regresamos la lista de mascotas :)
        cursor.close();


        AdaptadorPersonas adaptadorPersonas = new AdaptadorPersonas(personas);
        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setAdapter(adaptadorPersonas);

    }
}

Iteramos el cursor y vamos agregando un elemento al ArrayList. El momento en donde la magia ocurre es cuando llamamos a setAdapter; los demás métodos que tienen que ver con el RecyclerView son para agregar algunos diseños.

Conclusión

Con este ejercicio reforzamos un poco más los métodos que Android ofrece para trabajar con bases de datos. Como lo dije al inicio, si quieres uno más avanzado mira el CRUD de Mascotas.

Todo el código que se necesita está en GitHub en el link que puse al inicio.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

  • Hola en este ejemplo no entendí que editor de texto usaste para escribir el código y que dispositivo usaste una computadora o un dispositivo móvil? Espero tu respuesta saludos

Entradas recientes

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

3 días hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

3 días hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

3 días hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

3 días hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

3 días hace

Solución: Apache – Server unable to read htaccess file

Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…

4 días hace

Esta web usa cookies.