Tutorial CRUD Android + SQLite (XI): Utilizar ArrayAdapter para mostrar datos en ListView

Posted by in Programación Android

Siguiendo con el Tutorial Android + SQLite en la entrada anterior vimos cómo incluir un spinner con datos de una tabla relacionada, en esta veremos cómo utilizar un ArrayAdapter para recuperar los datos de una tabla SQLite y mostrarlos en el ListView.

Vamos a mejorar el código del tutorial definiendo una nueva clase que representará a cada una de las hipotecas así como las operaciones de base de datos, simplificando el código en las operaciones relacionadas con las hipotecas. Además crearemos una nueva clase que extienda de ArrayAdapter que utilizaremos como adaptador para mostrar datos en el ListView, evitando así el uso del CursorAdapter y la tan repetida advertencia startManaginCursor is deprecated. En esta entrada profundizaremos en los siguientes aspectos:

  • Renombrar la clase de la actividad principal
  • Crear una nueva clase Hipoteca
  • Modificar la aplicación para utilizar el objeto Hipoteca
  • Crear ArrayAdapter de Hipotecas
  • Utilizar ArrayAdapter para mostrar datos en ListView

 

1: Renombrar la clase de la actividad principal

Al comienzo del tutorial tomé la poco acertada decisión de llamar a la actividad principal de la misma Hipoteca. Ahora que vamos a crear una nueva clase para gestionar la entidad Hipoteca, me encuentro con que debería buscarle otro nombre con la confusión que esto podría originar. Como nunca es tarde para tomar una decisión acertada que clarifique el código, procederemos a renombrar la clase Hipoteca.java a HipotecaActivity.java. Por supuesto, lo hacemos desde la opción correspondiente de nuestro IDE para que modifique automáticamente todas las llamadas, el AndroidManifest, etc.

 

2: Crear una nueva clase Hipoteca

Tal y como indicábamos anteriormente, crearemos una clase con las propiedades de la hipoteca y con todos los métodos necesarios para gestionarla. Como era de esperar la llamaremos Hipoteca.

package com.sodenet.hipotecas;


import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;

public class Hipoteca {

    private Context context;

    private Long id;
    private String nombre;
    private String condiciones;
    private String contacto;
    private String email;
    private String telefono;
    private String observaciones;
    private boolean pasivo;
    private Long situacionId;

    public Hipoteca(Context context)
    {
        this.context = context;
    }

    public Hipoteca(Context context, Long id, String nombre, String condiciones, String contacto, String email, String telefono, String observaciones, boolean pasivo, Long situacionId) {
        this.context = context;
        this.id = id;
        this.nombre = nombre;
        this.condiciones = condiciones;
        this.contacto = contacto;
        this.email = email;
        this.telefono = telefono;
        this.observaciones = observaciones;
        this.pasivo = pasivo;
        this.situacionId = situacionId;
    }

    public Context getContext() {
        return context;
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public Long getId() {
        return id;
    }

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

    public String getNombre() {
        return nombre;
    }

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

    public String getCondiciones() {
        return condiciones;
    }

    public void setCondiciones(String condiciones) {
        this.condiciones = condiciones;
    }

    public String getContacto() {
        return contacto;
    }

    public void setContacto(String contacto) {
        this.contacto = contacto;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getTelefono() {
        return telefono;
    }

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

    public String getObservaciones() {
        return observaciones;
    }

    public void setObservaciones(String observaciones) {
        this.observaciones = observaciones;
    }

    public boolean isPasivo() {
        return pasivo;
    }

    public void setPasivo(boolean pasivo) {
        this.pasivo = pasivo;
    }

    public Long getSituacionId() {
        return situacionId;
    }

    public void setSituacionId(Long situacionId) {
        this.situacionId = situacionId;
    }

    public static Hipoteca find(Context context, long id)
    {
        HipotecaDbAdapter dbAdapter = new HipotecaDbAdapter(context);

        Cursor c = dbAdapter.getRegistro(id);

        Hipoteca hipoteca = Hipoteca.cursorToHipoteca(context, c);

        c.close();

        return hipoteca;
    }

    public static Hipoteca cursorToHipoteca(Context context, Cursor c)
    {
        Hipoteca hipoteca = null;

        if (c != null)
        {
            hipoteca = new Hipoteca(context);

            hipoteca.setId(c.getLong(c.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_ID)));
            hipoteca.setNombre(c.getString(c.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_NOMBRE)));
            hipoteca.setCondiciones(c.getString(c.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_CONDICIONES)));
            hipoteca.setContacto(c.getString(c.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_CONTACTO)));
            hipoteca.setEmail(c.getString(c.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_EMAIL)));
            hipoteca.setTelefono(c.getString(c.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_TELEFONO)));
            hipoteca.setObservaciones(c.getString(c.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_OBSERVACIONES)));
            hipoteca.setPasivo(c.getString(c.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_PASIVO)).equals("S"));
            hipoteca.setSituacionId(c.getLong(c.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_SITUACION)));
        }

        return hipoteca ;
    }

    private ContentValues toContentValues()
    {
        ContentValues reg = new ContentValues();

        reg.put(HipotecaDbAdapter.C_COLUMNA_ID, this.getId());
        reg.put(HipotecaDbAdapter.C_COLUMNA_NOMBRE, this.getNombre());
        reg.put(HipotecaDbAdapter.C_COLUMNA_CONDICIONES, this.getCondiciones());
        reg.put(HipotecaDbAdapter.C_COLUMNA_CONTACTO, this.getContacto());
        reg.put(HipotecaDbAdapter.C_COLUMNA_EMAIL, this.getEmail());
        reg.put(HipotecaDbAdapter.C_COLUMNA_TELEFONO, this.getTelefono());
        reg.put(HipotecaDbAdapter.C_COLUMNA_OBSERVACIONES, this.getObservaciones());
        reg.put(HipotecaDbAdapter.C_COLUMNA_PASIVO, (this.isPasivo())?"S":"N");
        reg.put(HipotecaDbAdapter.C_COLUMNA_SITUACION, this.getSituacionId());

        return reg;
    }

    public long save()
    {
        HipotecaDbAdapter dbAdapter = new HipotecaDbAdapter(this.getContext());

        // comprobamos si estamos insertando o actualizando según esté o no relleno el identificador
        if ((this.getId() == null) || (!dbAdapter.exists(this.getId())))
        {
            long nuevoId = dbAdapter.insert(this.toContentValues());

            if (nuevoId != -1)
            {
                this.setId(nuevoId);
            }
        }
        else
        {
            dbAdapter.update(this.toContentValues());
        }

        return this.getId();
    }

    public long delete()
    {
        // borramos el registro
        HipotecaDbAdapter dbAdapter = new HipotecaDbAdapter(this.getContext());

        return dbAdapter.delete(this.getId());
    }
}

 

Como podéis observar, además de las propiedades, el constructor y los setters/getters he incluido los métodos find, save y delete para encapsular las operaciones de base de datos.

También he incluido los métodos cursorToHipoteca que permite obtener un objeto Hipoteca a partir de un cursor y toContentValues que devuelve un objeto ContentValues de la Hipoteca para facilitar las operaciones con la HipotecaDbAdapter que gestiona las operaciones de base de datos.

En la nueva clase se utiliza el método exists de la clase HipotecaDbAdapter que todavía no tenemos disponible, por lo que tenemos que incluirlo.

...
...
...
    public boolean exists(long id) throws SQLException
    {
        boolean exists ;

        if (db == null)
            abrir();

        Cursor c = db.query( true, C_TABLA, columnas, C_COLUMNA_ID + "=" + id, null, null, null, null, null);

        exists = (c.getCount() > 0);

        c.close();

        return exists;
    }
...
...
...

 

3: Modificar la aplicación para utilizar el objeto Hipoteca

Una vez creada la nueva clase, ya tenemos la posibilidad de trabajar con objetos Hipoteca en la aplicación y por tanto la posibilidad de simplificar el código. Vamos a ello:

Simplificamos el método consultar de la clase HipotecaFormulario

...
...
...
private void consultar(long id)
{
    //
    // Consultamos la hipoteca por el identificador
    //
    Hipoteca hipoteca = Hipoteca.find(this, id);

    nombre.setText(hipoteca.getNombre());
    condiciones.setText(hipoteca.getCondiciones());
    contacto.setText(hipoteca.getContacto());
    telefono.setText(hipoteca.getTelefono());
    email.setText(hipoteca.getEmail());
    observaciones.setText(hipoteca.getObservaciones());
    pasivo.setChecked(hipoteca.isPasivo());
    situacion.setSelection(getItemPositionById(cursorListaSituacion, hipoteca.getSituacionId()));
}
...
...
...

 

Simplificamos el método guardar de la clase HipotecaFormulario

...
...
...
private void guardar()
{
    Hipoteca hipoteca ;

    if (this.modo == HipotecaActivity.C_EDITAR)
    {
        hipoteca = Hipoteca.find(this, this.id);
    }
    else
    {
        hipoteca = new Hipoteca(this) ;
    }

    hipoteca.setNombre(nombre.getText().toString());
    hipoteca.setCondiciones(condiciones.getText().toString());
    hipoteca.setContacto(contacto.getText().toString());
    hipoteca.setTelefono(telefono.getText().toString());
    hipoteca.setEmail(email.getText().toString());
    hipoteca.setObservaciones(observaciones.getText().toString());
    hipoteca.setPasivo(pasivo.isChecked());
    hipoteca.setSituacionId(situacion.getSelectedItemId());

    hipoteca.save();

    if (modo == HipotecaActivity.C_CREAR)
    {
        Toast.makeText(HipotecaFormulario.this, R.string.hipoteca_crear_confirmacion, Toast.LENGTH_SHORT).show();
    }
    else if (modo == HipotecaActivity.C_EDITAR)
    {
        Toast.makeText(HipotecaFormulario.this, R.string.hipoteca_editar_confirmacion, Toast.LENGTH_SHORT).show();
    }

    //
    // Devolvemos el control
    //
    setResult(RESULT_OK);
    finish();
}
...
...
...

 

4: Crear ArrayAdapter de Hipotecas

Creamos la clase HipotecasAdapter extendiendo de ArrayAdapter que posteriormente utilizaremos para llenar el ListView.

package com.sodenet.hipotecas;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;


import java.util.ArrayList;


public class HipotecasAdapter extends ArrayAdapter<Hipoteca>
{
    private static class ViewHolder {
        TextView text1;
    }

    public HipotecasAdapter(Context context, ArrayList<Hipoteca> hipotecas) {
        super(context, android.R.layout.simple_dropdown_item_1line, hipotecas);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        Hipoteca hipoteca = getItem(position);

        ViewHolder viewHolder;

        if (convertView == null)
        {
            viewHolder = new ViewHolder();
            LayoutInflater inflater = LayoutInflater.from(getContext());
            convertView = inflater.inflate(android.R.layout.simple_dropdown_item_1line, parent, false);
            viewHolder.text1 = (TextView) convertView.findViewById(android.R.id.text1);
            convertView.setTag(viewHolder);
        }
        else
        {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        viewHolder.text1.setText(hipoteca.getNombre());

        return convertView;
    }

    @Override
    public long getItemId(int position)
    {
        return getItem(position).getId();
    }
}

 

5:Utilizar ArrayAdapter para mostrar datos en ListView

Modificamos la clase HipotecaDbAdapter para incorporar una función que obtenga un ArrayList de objetos Hipoteca.

...
...
    public ArrayList<Hipoteca> getHipotecas(String filtro)
    {
        ArrayList<Hipoteca> hipotecas = new ArrayList<Hipoteca>();

        if (db == null)
            abrir();

        Cursor c = db.query(true, C_TABLA, columnas, filtro, null, null, null, null, null);

        for(c.moveToFirst(); !c.isAfterLast(); c.moveToNext())
        {
            hipotecas.add(Hipoteca.cursorToHipoteca(contexto, c));
        }

        c.close();

        return hipotecas;
    }
...
...

Modificamos el método consultar de la clase HipotecaActivity para utilizar HipotecasAdapter para mostrar los datos en el ListView.

...
...
    private void consultar()
    {
        hipotecasAdapter = new HipotecasAdapter(this, dbAdapter.getHipotecas(filtro));

        lista.setAdapter(hipotecasAdapter);
    }
...
...

También modificamos el onCreateContextMenu para obtener el identificador del registro del nuevo adaptador

...
...
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
{
	super.onCreateContextMenu(menu, v, menuInfo);

	menu.setHeaderTitle(hipotecasAdapter.getItem(((AdapterContextMenuInfo) menuInfo).position).getNombre());
	menu.add(Menu.NONE, C_VISUALIZAR, Menu.NONE, R.string.menu_visualizar);
	menu.add(Menu.NONE, C_EDITAR, Menu.NONE, R.string.menu_editar);
	menu.add(Menu.NONE, C_ELIMINAR, Menu.NONE, R.string.menu_eliminar);
}
...
...

Con estos cambios, tras actualizar los imports para eliminar los que ya no son necesarios e incorporar los nuevos, hemos finalizado. Ahora basta con ejecutar la aplicación y comprobar que sigue funcionando como antes de los cambios.


 
Si tienes alguna pregunta o algo que aportar no lo dudes … ¡tienes los comentarios a tu disposición!