Tutorial CRUD Android + SQLite (II): Mostrar datos en ListView

Siguiendo con el Tutorial Android + SQLite en la entrada anterior vimos la definición y creación de la base de datos SQLite para la aplicación CRUD de ejemplo que consistía en registrar las condiciones ofrecidas por las entidades bancarias para la solicitud de una hipoteca. En la entrada actual trataremos la visualización de los registros de la base de datos SQLite en un componente ListView.
 

1: HipotecaDbAdapter

Definimos la clase HipotecaDbAdapter para gestionar las operaciones de la entidad HIPOTECA en la base de datos SQLite.
android_sqlite_listview_1

package com.sodenet.hipotecas;

import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;

public class HipotecaDbAdapter {

	/**
	 * Definimos constante con el nombre de la tabla
	 */
	public static final String C_TABLA = "HIPOTECA" ;

	/**
	 * Definimos constantes con el nombre de las columnas de la tabla
	 */
	public static final String C_COLUMNA_ID	= "_id";
	public static final String C_COLUMNA_NOMBRE = "hip_nombre";
	public static final String C_COLUMNA_CONDICIONES = "hip_condiciones";
	public static final String C_COLUMNA_CONTACTO = "hip_contacto";
	public static final String C_COLUMNA_EMAIL = "hip_email";
	public static final String C_COLUMNA_TELEFONO = "hip_telefono";
	public static final String C_COLUMNA_OBSERVACIONES = "hip_observaciones";

	private Context contexto;
	private HipotecaDbHelper dbHelper;
	private SQLiteDatabase db;

	/**
	 * Definimos lista de columnas de la tabla para utilizarla en las consultas a la base de datos
	 */
	private String[] columnas = new String[]{ C_COLUMNA_ID, C_COLUMNA_NOMBRE, C_COLUMNA_CONDICIONES, C_COLUMNA_CONTACTO, C_COLUMNA_EMAIL, C_COLUMNA_TELEFONO, C_COLUMNA_OBSERVACIONES} ;

	public HipotecaDbAdapter(Context context)
	{
		this.contexto = context;
	}

	public HipotecaDbAdapter abrir() throws SQLException
	{
		dbHelper = new HipotecaDbHelper(contexto);
		db = dbHelper.getWritableDatabase();
		return this;
	}

	public void cerrar()
	{
		dbHelper.close();
	}

	/**
	 * Devuelve cursor con todos las columnas de la tabla
	 */
	public Cursor getCursor() throws SQLException
	{
		Cursor c = db.query( true, C_TABLA, columnas, null, null, null, null, null, null);

		return c;
	}
}

 

2: HipotecaCursorAdapter

Definimos la clase HipotecaCursorAdapter que utilizaremos desde la Activity Hipoteca para alimentar el ListView con los datos obtenidos a traves de la clase HipotecaDbAdapter.
android_sqlite_listview_2

package com.sodenet.hipotecas;

import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.TextView;

public class HipotecaCursorAdapter extends CursorAdapter
{

	private HipotecaDbAdapter dbAdapter = null ;

	public HipotecaCursorAdapter(Context context, Cursor c)
	{
		super(context, c);
		dbAdapter = new HipotecaDbAdapter(context);
		dbAdapter.abrir();
	}

	@Override
	public void bindView(View view, Context context, Cursor cursor)
	{
		TextView tv = (TextView) view ;

		tv.setText(cursor.getString(cursor.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_NOMBRE)));
	}

	@Override
	public View newView(Context context, Cursor cursor, ViewGroup parent)
	{
		final LayoutInflater inflater = LayoutInflater.from(context);
		final View view = inflater.inflate(android.R.layout.simple_dropdown_item_1line, parent, false);

		return view;
	}
}

 

3: Diseño Layout Activity Principal

En la entrada anterior creamos la Activity Hipoteca dejando el diseño de la misma en blanco. Ahora vamos a editar el layout de esta Activity posicionando un ListView que utilizaremos para mostrar los registros de la base de datos SQLite.

android_sqlite_listview_3

Editamos archivo res/layout/activity_hipoteca.xml dejándolo como sigue a continuación:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".Hipoteca" >

    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@id/android:empty"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/lista_vacia" />
    
</LinearLayout>

Añadimos al archivo res/values/strings.xml la definición de string que utilizamos cuando la lista está vacía.

<string name="lista_vacia">Sin Datos</string>

 

4: Enlazar ListActivity con la base de datos SQLite

Modificamos la Activity principal de la aplicación para que herede de ListActivity, ya que simplificará el tratamiento de la lista en próximas modificaciones.
En el método onCreate obtenemos la referencia a la ListView incluida en el layout y creamos y preparamos el adaptador dbAdapter para gestionar las operaciones sobre la entidad HIPOTECA en la base de datos SQLite.
El método consultar() se encargará de vincular el CursorAdapter hipotecaAdapter a la ListView lista.

package com.sodenet.hipotecas;

import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.view.Menu;
import android.widget.ListView;

public class Hipoteca extends ListActivity {

	private HipotecaDbAdapter dbAdapter;
    private Cursor cursor;
    private HipotecaCursorAdapter hipotecaAdapter ;
    private ListView lista;

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

		lista = (ListView) findViewById(android.R.id.list);

		dbAdapter = new HipotecaDbAdapter(this);
		dbAdapter.abrir();

		consultar();
	}

	private void consultar()
	{
		cursor = dbAdapter.getCursor();
		startManagingCursor(cursor);
		hipotecaAdapter = new HipotecaCursorAdapter(this, cursor);
		lista.setAdapter(hipotecaAdapter);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.hipoteca, menu);
		return true;
	}
}

 

5: Ejecución de la aplicación

¡Ya está todo listo! Ahora basta con ejecutar la aplicación en el emulador.

android_sqlite_listview_4


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

  • Pingback: Bitacoras.com()

  • Pingback: Tutorial CRUD Android + SQLite: Mostrar datos en Formulario | Anotaciones de un programador()

  • Carlos

    Hola en estas partes de codigo tengo super( de CursorAdapter) y startManagingCursor, deprecated a partir de la API 11. Soy novato en la programacion en android y entiendo que significan, pero no se como solucionarlo. Un saludo!


    public class HipotecaCursorAdapter extends CursorAdapter
    {
    ...
    {
    super(context, c);
    dbAdapter = new HipotecaDbAdapter(context);
    dbAdapter.abrir();
    }


    public class Hipoteca extends ListActivity {
    ...
    private void consultar()
    {
    cursor = dbAdapter.getCursor();
    startManagingCursor(cursor);
    hipotecaAdapter = new HipotecaCursorAdapter(this, cursor);
    lista.setAdapter(hipotecaAdapter);
    }

    • pmon

      Conforme se publican nuevas versiones de la API de Android se van marcando algunas clases o métodos en desuso y recomendando la utilización de otras nuevas. No obstante, éstos métodos pueden seguir utilizándose.

      Un saludo

    • JC

      Pues yo intente usarlo así nomas con la API 17 y no me instalaba la aplicación, lo que hice fue bajarme la API 10 ya que hasta ese nivel de API todavía son usables esos comandos, y funciono todo correctamente.

  • rqt

    A mi me pasa exactamente lo mismo con el super y starManagingCursor, y aunque tengo el código igual, me da un fallo al ejecutar, me sale una pantalla en el emulador diciéndome que la ejecución se ha parado. No se si será por los fallos que comenta Carlos u otros.

    • pmon

      Deberías revisar el LogCat que te mostrará información detallada del error producido.

      Un saludo.

  • http://twitter.com/_Soldier SoldierCorp

    Muy buen artículo pero tengo una duda, he estado siguiendo la serie de tutoriales desde el 1 pero ahora con este en la actividad Hipoteca me dice “startManagingCursor(cursor)” y el mensaje es: The method startManahingCursor(cursor) from the type Activity is deprecated. Y en HipotecaCursorAdapter me da warning en “super(context, c);” y el mensaje es: The constructor HipotecaCursorAdapter(Context, Cursor) is deprecated.

    Espero puedas ayudarme.

    Saludos.

    • Pascual Montesinos

      Supongo que te refieres a los warnings, conforme se publican nuevas versiones de la API de Android se van marcando algunas clases o métodos en desuso y recomendando la utilización de otras nuevas. No obstante, éstos métodos pueden seguir utilizándose.

      Un saludo

  • Francisco Fernández Ruiz

    Hola

    Primero felicitarte por el tuto está muy bien.

    Me surge una duda….como hariamos para mostrar en el listview dos lineas de la base de datos?

    Por ejemplo el nombre y condiciones?

    • Pascual Montesinos

      Hola, Francisco.

      Para mostrar dos líneas en el ListView, deberías utilizar en el método newView de la clase HipotecaCursorAdapter un layout con varios elementos. Podrías definirte uno personalizado o bien utilizar el predefinido por android R.layout.two_line_list_item. Después en el método bindView tenemos que obtener los elementos del layout y rellenarlos.

      Adjunto cómo quedaría el ejemplo incluyendo el nombre y el contacto:

      @Override
      public void bindView(View view, Context context, Cursor cursor)
      {
      TextView tv1 = (TextView) view.findViewById(R.id.text1) ;
      TextView tv2 = (TextView) view.findViewById(R.id.text2) ;

      tv1.setText(cursor.getString(cursor.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_NOMBRE)));
      tv2.setText(cursor.getString(cursor.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_CONTACTO)));

      if (cursor.getString(cursor.getColumnIndex(HipotecaDbAdapter.C_COLUMNA_PASIVO)).equals(“S”))
      {
      tv1.setTextColor(Color.GRAY);
      tv2.setTextColor(Color.GRAY);
      }
      else
      {
      tv1.setTextColor(Color.BLACK);
      tv2.setTextColor(Color.BLACK);
      }
      }

      @Override
      public View newView(Context context, Cursor cursor, ViewGroup parent)
      {
      final LayoutInflater inflater = LayoutInflater.from(context);
      final View view = inflater.inflate(R.layout.two_line_list_item, parent, false);

      return view;
      }

      Un saludo.

  • Gustavo Arvizu Amezcua

    Hola Pascual.

    Primero que nada, te agradezco que compartas tus conocimientos con todo el que te lea.

    Por otro lado, quiero consultarte algo. Cuando ejecuto este código en Android 2.3.x, los textos del ListView no aparecen, sin embargo si tocas cualquier renglón, entonces si se muestra el texto.

    En cambio si lo corres en Android 4.2.2, esto no sucede. Esto lo he probado directamente en un teléfono con 2.3.7, como en un emulador con 2.3.3.

    ¿Habías visto esto?, y en todo caso ¿Sabrás como resolverlo?

    Saludos

    • Pascual Montesinos

      Hola Gustavo.

      El tema que comentas posiblemente se deba a la coincidencia de colores del tema por defecto para los elementos, ya que se visualiza cuando lo seleccionas.

      Este problema está resuelto en el paso 4 de la octava entrada del tutorial: http://notasprogramacion.sodenet.es/tutorial-crud-android-sqlite-actualizar-base-de-datos

      En ese paso en concreto, dependiendo de la situación del registro se muestra en gris o en negro, de ese modo cambiamos el color por defecto del tema y ya se visualiza.

      Un saludo.

  • Dave Espejo

    Hola! Buenisimo tu tutorial..!

    Tengo un problema, cuando quiero ejecutar la app se abre, aparece la pantalla en blanco y luego crashea (Sorry! This app bla bla bla) no logro ver la base de datos en el listView. Si consulto la base de datos desde el ordenador puedo ver que la base de datos se ha cargado correctamente pero no puedo visualizarla.

    En la clase “HipotecaDbAdapter” , en el método “abrir()” me marca un error :

    public HipotecaDbAdapter abrir() throws SQLException{

    dbHelper = new HipotecaDbHelper(contexto); El ide me propone como solución –> (contexto, null, null, 0);

    db = dbHelper.getWritableDatabase();
    return this;

    }

    Estoy desorientado… Gracias de antemano

    • Dave Espejo

      Solucionado :3 habia escrito mal una clase :)

      • Estuardo León

        ¿Qué clase? porque a mi me pasa lo mismo.

  • Carlos Hernan Guajardo Ramirez

    hola me puede ayudar tengo un problema con un proyecto que estoy haciendo junto al listview tengo que poner una opción que me permita suscribir y de suscribir a ese listview

  • Leo

    Hola una pregunta quiero obtener todos los nombres de la hipoteca en un string [ ] para usar SearchView para buscar en la listview pero creo que no comprendi bien en que parte puedo obtener este registro para cargarlo en el string

    • Pascual Montesinos

      Hola, Leo.

      Puedes recorrer todos los elementos del cursor, y hacer con ellos lo que quieras. Recuerda que para recorrer el cursor puedes hacerlo así:

      for(c.moveToFirst(); !c.isAfterLast(); c.moveToNext())

      Un saludo.

      • Leo

        Hola gracias por tu respuesta pero eso me genero otra pregunta no puedo usar la parte de

        cursor = dbAdapter.getCursor();
        startManagingCursor(cursor);
        hipotecaAdapter = new HipotecaCursorAdapter(this, cursor);
        lista.setAdapter(hipotecaAdapter);

        de consulta para llenar

        mListView.setAdapter(new ArrayAdapter(this,
        android.R.layout.simple_list_item_1,mStrings));
        mListView.setTextFilterEnabled(true);
        setupSearchView();

        ya que cursor de dbAdapter deberia traer toda la info de la tabla la intencion es que un SearchView filtre la tabla a medida que colocamos letras

  • Lorena Cañon

    Siempre me sale Sin datos :(

  • Drawil

    ¿Como podría generear una tabla que mostrase en cada columna los datos deseados de las filas de la base de datos? Que metodo es el que seria el más util.¿ se podria tener un listener en la fila como si fuera un boton?

  • Drawil

    Oye estoy probando con dos tablas y he cambiado “_id” del create por “E_ID” para diferenciar un id del otro, la base de datos la construye bien, pero al generar el ListActivity en Hipoteca me sale error, concretamente en la linea 26 q es el consultar(), y eso que lo he cambiado en el Adapter, public static final String C_COLUMNA_ID = “E_id”;
    ¿Tengo que cambiar algo más del codigo para que pille el id?(he borrado el R.java tambien y nada, ademas de borrar la app del movil y lanzarla de nuevo) Ayuda! Gracias de ante mano

    • Pascual Montesinos

      No es posible, la clase CursorAdapter necesita el campo _id para funcionar, así lo dice http://developer.android.com/reference/android/widget/CursorAdapter.html

      Un saludo.

      • Drawil

        jaja gracias ya vi que tenía que nombrarlo _id si o si, bueno siempre puedo referirme al id para difenciar uno de otro id asi “TABLA._id” en el caso de que necesite hacer, por ejemplo, una FOREIGN KEY. Eso espero que SQLite me lo pille por q ya vi que ALTER CONSTRAINS no lo acepta xD
        gracias, un saludo

  • Leo

    Hola una pregunta estoy terminando el tuto completo y quisiera poder agregar fotos de cámara y todo bien pero tengo el problema de que siempre que tomo la foto re escribe la anterior por que no cambia el nombre y quisiera mas bien que cada que le de guardar la foto tome el nombre del _id ahora una pregunta como sacar e ultimo id de la tabla cuando estoy apunto de guardar?

  • jorge

    La única duda seria.. porque llamas dos veces al metodo abrir() de la clase PolizaDbAdapter. ?

  • Diego ALberto Lara Salto

    Hola, yo de nuevo muchas gracias de nuevo por tu ayuda.

    Tengo una duda, estoy actualizando el proyecto Hipoteca y como ahora estoy implementando NavigationDrawer pues no se como hacer para pasar las activitys a fragments, por ejemplo, paso el código para cargar el listView de la activity principal Hipoteca, actualizo así:
    cursor = dbAdapter.getCursor();

    getActivity().startManagingCursor(cursor);

    hipotecaAdapter = new HipotecaCursorAdapter(getActivity().getBaseContext(), cursor);

    lista.setAdapter(hipotecaAdapter);

    y aunque no me marca ningún error pero se sale la aplicación.
    ¿Que estás haciendo Tu en estos casos para actualizar la aplicación?
    Gracias. Saludos desde México!

  • Fulanito Oskar

    Hola, ¿puedes pasarme el proyecto completo?

    Mi correo es fulanito.oskr@gmail.com

    • Pascual Montesinos

      Puedes descargarlo de github.

      Un saludo.

  • Virginia Pastrán

    Hola! Has hecho una buena guía con este ejemplo, pero tengo una duda:

    Al adaptar tu ejemplo a uno que yo quiero hacer, el método “startManagingCursor(cursor)” que se usa en el método “consultar()”, está DEPRECATED, con lo que eclipse automáticamente me lo tacha y ni siquiera me deja correr la aplicación. Buscando en Intenet he encontrado que Google DESAPRUEBA este y otros métodos relacionados.

    MI PREGUNTA ES: qué método(s) debo usar entonces para corregir esto???

    Gracias!

    • Pascual Montesinos

      Hola, buenas tardes.

      Después de mucho tiempo, estoy escribiendo otra entrada en la que explico como mostrar los datos en el ListView utilizando un ArrayAdapter en vez del CursorAdapter.

      Con esta modificación, ya no es necesario utilizar un cursor en la activity y gestionarlo con startManagigCursror. Puedes ver los cambios ya en github.

      Un saludo.

  • Marcos.

    Hola, lo primero muchas gracias por este magnífico tutorial.

    Estoy intentando implementar la base de datos en una aplicación que usa ActionbarActivity desde la importacion de las librerias de soporte de compatibilidad de android. Y tengo unas pestañas que dependiendo de la pulsación cargan un layout u otro. Por eso la actividad principal hereda el ActionbarActivity y no puede heredar ListActivity.

    ¿Hay alguna forma de adaptarlo a este caso?

    Gracias de antemano!

  • Javier Girón

    Hola! Tengo un problema. He copiado el codigo tal y como está aquí pero al iniciar la aplicación no me cargan los datos. De hecho el problema creo que es en el “HipotecaDbAdapter” en esta linea:

    public HipotecaDbAdapter abrir() throws SQLException

    {

    dbHelper = new HipotecaDbHelper(contexto);

    db = dbHelper.getWritableDatabase();

    return this;

    }

    Debería entrar en HipotecaDbHelper y crear la base de datos, pero no lo hace y la lista me aparece vacía. ¿Alguien me puede decir a que es debido?

    He descargado el proyecto entero tal cual y me ocurre lo mismo.

Post Navigation