ListView o listado en Android


Este tutorial está indicado para todos lo que ya hayan buceado un poco en Android. Sobre todo para adentrarnos en los ListView o listado en Android. Se dará por sentado ciertos conocimientos muy básicos, cuyo apoyo pueden servirse de tutoriales anteriores como el de saber qué es una Actividad. Si no tienes mucho tiempo o quieres un Snippet de código para hacer un listado rápidamente, entonces te recomiendo que vayas directamente al artículo de listado en pocas líneas; si por el contrario quieres aprenderlo todo sobre listados de Android continuar leyendo es la opción correcta.

“Aunque todo en el universo tienda al caos, siempre es bueno ponerle un orden para saber interpretarlo”. No es la mejor definición de listado, pero si una bonita alegoría al mismo. Un listado es eso, un conjunto de datos ordenados, para que sea sencillo indagar en ellos.

Este tutorial se basará en describir como hacer un listado en Android: en el que tenemos un número arbitrario de datos -número exacto de entradas que no conocemos, bien porque obtengamos los datos de Internet, o estén en una base de datos que va creciendo, etc- de aves que queremos ordenar en un listado. Cuyas entradas queremos hacer a nuestro antojo con el nombre del ave como titular, una pequeña descripción y una imagen asociada a cada uno (Véase la imagen siguiente, para entender de un vistazo lo que se quiere conseguir).

Ejemplo de listado final - www.jarroba.com

Y no contentos con esto, queremos que además sea seleccionable cada elemento del listado.

Ejemplo de listado final seleccionado un elemento - www.jarroba.com

Para mostrar más información en un Toast (también podríamos abrir otra Activity con información extra, o lo que queramos) del elemento seleccionado.

Ejemplo de listado final seleccionado un elemento 2 - www.jarroba.com

Vamos, que construiremos un ListView de generación dinámica de contenidos (Un ejemplo estático lo tienes en la página oficial de desarrolladores de Android), deseable el 90% de la veces por un programador Android. Y sí, las imágenes y textos del ejemplo están obtenidos de la Wikipedia.

Como haremos esto de una manera sencilla y óptima. Primero lo entenderemos y luego lo haremos.

¿Qué es lo que queremos hacer? Queremos un listado de todos los elementos/entradas individuales que me den la gana (entre cero e infinito 😉 ). De lo real al concepto mental sería la siguiente imagen.

Idea de listView - www.jarroba.com

Todos las entradas son iguales, ¿Sería maravilloso que se pudiera diseñar una única entrada y luego que el resto sean "un copiar y pegar"? Aunque sea por vaguería, la respuesta es: debemos como buenos programadores.

Descomponer ListView en entradas - www.jarroba.com

Ya tenemos dividido lo que queremos hacer. Ahora, la lógica nos dice que en el diseño hacia delante, tendremos dos Layouts uno principal que contendrá varias veces la copia del segundo:

  • Uno con la entrada suelta, con el diseño que queramos. Será la unidad que se copiará en el interior del listado. Lo llamaremos en este ejemplo “entrada.xml”.
  • Otro con el listado, que solo dispondrá de tal. Con los “huecos” esperando para contener la copia del diseño de la entrada; y cada entrada con unos datos diferentes. A este contenedor de entradas lo llamaremos “listado.xml”.

Copia de la View para el ListView - www.jarroba.com

Haremos el diseño de “entrada.xml”. Para el ejemplo haremos el siguiente Layout, que evidentemente podremos hacer a nuestro antojo, con los campos que queramos, imágenes, botones, checkbox, spinner, etc. Al diseñar éste, pensemos, no en el contenido de cada entrada, sino como haremos todas las entradas para que salgan iguales. Pues este será replicado para todas la entradas.

Para el ejemplo, la idea de una entrada es la siguiente:

View de la entrada descompuesto - www.jarroba.com

Y su código asociado para generar la vista de una entrada sería este (Nota: por reducir código y que se entienda mejor, hemos optado por poner los Strings directamente; esto está mal hecho y deberían ir al fichero “strings.xml”). Evidentemente ponemos los “id” para luego referenciarlos y llenar cada una de las entradas con sus datos correspondientes.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/imageView_imagen"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:adjustViewBounds="true"
        android:scaleType="fitXY"
        android:contentDescription="Descripción del contenido de la imagen"
        android:src="@android:drawable/ic_menu_gallery" />

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/textView_superior"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Large Text"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/textView_inferior"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Small Text"
            android:textAppearance="?android:attr/textAppearanceSmall" />

    </LinearLayout>

</LinearLayout>

¿Fácil? No. Más fácil es “listado.xml”. En este ejemplo nos bastará con que usemos ListView, que será el contenedor de las entradas.

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ListView_listado"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
</ListView>

Falta que hagamos la lógica del programa. La lógica que nos cargará los datos y nos construirá el listado. Para esto tendremos una Actividad que será la que muestre el listado. Para no liar las cosas lo haremos en el ejemplo en la clase “MainActivity.java”. Esta hará uso de otras dos. Una que encapsule los datos de la entrada, cuyo nombre pondremos como “Lista_entrada.java”. Y otra que será la que adapte las entradas a la lista, y será nombrada como “Lista_adaptador.java”.

Terminaremos teniendo los siguientes archivos en el explorador de paquetes. Donde los marcados serán los que usaremos en este ejemplo. Cabe indicar que las imágenes las estamos insertando directamente para no complicar más el ejemplo, pero esta forma de construir el listado dinámicamente también funcionaría si las imágenes se descargaran de internet, se obtuvieran de la memoria del teléfono, etc.

Lista proyecto ListView - www.jarroba.com

Empezaremos a definir “Lista_entrada.java”. ¿Para qué sirve? Sabemos que nos llegarán unos datos, y que nos interesan los siguientes para cada entrada: imagen, título y descripción. Por lo que haremos unos paquetes de datos para cada uno de los conjuntos de la entrada. Estos paquetes serán objetos de la clase “Lista_entrada.java”.

Clase adaptador ListView - www.jarroba.com

Para hacernos una idea, imaginemos que tenemos tres pájaros. Cada uno con: título, descripción e imagen. Tendremos tres objetos de la clase “Lista_entrada.java”, cada uno almacenará sus datos. Pero no confundamos, esto no está asignado todavía a la entrada de la vista -de la interfaz- sino que son grupos para separar la información. Estos grupos se suelen llamar manejadores o en inglés “handler”.

Objetos clase adaptador - www.jarroba.com

El código siguiente contiene lo que es la encapsulación de los datos, que coinciden con los explicados:

  • Título, con nombre de variable como “textoEncima” para especificar en cuál de los dos TextViews de la vista tendrá que ser colocado.
  • Descripción, la variable la llamaremos como “textoDebajo”.
  • Imagen, y almacenaremos la variable “idImagen”, para referenciara a la imagen. Solo guardaremos el id, ya que solo guardaremos el identificador de la imagen y no la imagen en sí (para este ejemplo no lo complicamos y guardamos el identificador, pero si queremos podremos guardar un Drawable, un Bitmap, etc).

Este manejador tendrá las variables de los View que hayamos declarado en el Layout “entrada.xml”. Repito, aquí no lo referenciaremos, es solo un contenedor que separa unos datos de otros.

Si nos fijamos en el su código, solo son variables, con sus getters y de setter el mismo constructor. No tiene más la clase, es así de simple (aquí, para que se entienda mejor, ponemos los getters y setters; Android recomienda por optimizar hacer variables globales publicas y olvidarnos de getters y setters, con lo que sería todavía mucho más simple este código).

package jarroba.ramon.listado;

public class Lista_entrada {
	private int idImagen; 
	private String textoEncima; 
	private String textoDebajo; 

	public Lista_entrada (int idImagen, String textoEncima, String textoDebajo) { 
	    this.idImagen = idImagen; 
	    this.textoEncima = textoEncima; 
	    this.textoDebajo = textoDebajo; 
	}

	public String get_textoEncima() { 
	    return textoEncima; 
	}

	public String get_textoDebajo() { 
	    return textoDebajo; 
	}

	public int get_idImagen() {
	    return idImagen; 
	} 
}

¿Cómo encapsulamos los datos que queramos en este Handler? Muy sencillo, ya verás.

Si creamos el objeto “Lista_entrada” tal cual, lo haríamos de la siguiente manera:

new Lista_entrada(R.drawable. imagen, "TÍTULO", "Descripción");

¿Dónde asignamos el objeto? ¿Cuántos objetos vamos a tener de estos? La respuesta es en una lista de Java, más concretamente en un ArrayList.

En este ejemplo lo haremos directamente sobre la clase “MainActivity.java” como ejemplo la siguiente (Nota: lo que se muestra a continuación es un trozo de la clase “MainActivity.java”, se muestra completa al final del artículo). Aquí un ejemplo de como añadir la información de las tres aves al ArrayList:

package jarroba.ramon.listado;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.listado);

        ArrayList<Lista_entrada> datos = new ArrayList<Lista_entrada>();  

        datos.add(new Lista_entrada(R.drawable.im_buho, "BUHO", "Búho es el nombre común de aves de la familia Strigidae, del orden de las estrigiformes o aves rapaces nocturnas. Habitualmente designa especies que, a diferencia de las lechuzas, tienen plumas alzadas que parecen orejas."));
        datos.add(new Lista_entrada(R.drawable.im_colibri, "COLIBRÍ", "Los troquilinos (Trochilinae) son una subfamilia de aves apodiformes de la familia Trochilidae, conocidas vulgarmente como colibríes, quindes, tucusitos, picaflores, chupamirtos, chuparrosas, huichichiquis (idioma nahuatl), mainumby (idioma guaraní) o guanumby. Conjuntamente con las ermitas, que pertenecen a la subfamilia Phaethornithinae, conforman la familia Trochilidae que, en la sistemática de Charles Sibley, se clasifica en un orden propio: Trochiliformes, independiente de los vencejos del orden Apodiformes. La subfamilia Trochilinae incluye más de 100 géneros que comprenden un total de 330 a 340 especies."));
        datos.add(new Lista_entrada(R.drawable.im_cuervo, "CUERVO", "El cuervo común (Corvus corax) es una especie de ave paseriforme de la familia de los córvidos (Corvidae). Presente en todo el hemisferio septentrional, es la especie de córvido con la mayor superficie de distribución. Con el cuervo de pico grueso, es el mayor de los córvidos y probablemente la paseriforme más pesada; en su madurez, el cuervo común mide entre 52 y 69 centímetros de longitud y su peso varía de 0,69 a 1,7 kilogramos. Los cuervos comunes viven generalmente de 10 a 15 años pero algunos individuos han vivido 40 años. Los juveniles pueden desplazarse en grupos pero las parejas ya formadas permanecen juntas toda su vida, cada pareja defendiendo un territorio. Existen 8 subespecies conocidas que se diferencian muy poco aparentemente, aunque estudios recientes hayan demostrado diferencias genéticas significativas entre las poblaciones de distintas regiones."));
    }

}

Todavía no hemos acabado con la clase “MainActivity.java”. Faltaría decirle que queremos hacer con el ArrayList, que será enviárselo a la lista para que lo reconstruya y la de forma.

A toda ListView hay que pasarle un adaptador con los datos y que herede de “BaseAdapter” (Son cosas de Android…).

Antes un inciso. Hemos trabajado y conocemos la pesadez de hacer el adaptador de un listado de manera dinámica. Por eso www.jarroba.com quiere haceros un regalo, con el siguiente ahorro de tiempo y de comerse la cabeza. En todos los ejemplos que he visto por ahí, construyen un adaptador independiente para cada handler para este tipo de listas simples. Y yo he dicho: no, nunca más, no es necesario, un solo adaptador vale para todas las listas con entradas personalizadas que queramos (o al menos todas con las que he trabajado). A continuación les regalo el código, que en apariencia es sencillo; lo que sí es muy fácil de utilizar. Es el trabajo de mucho tiempo, errores y experiencia. Puede que sea mejorable, por lo que si descubres y nos lo quieres contar, o descubro una manera mejor actualizaré este tutorial. Pero por ahora no he visto nada más cómodo para trabajar con listas. Por supuesto, eres libre de modificarlo, proponer mejoras y de usarlo.  Nota: este adaptador "universal" es solo para listas simples con vistas complejas, lo que es que van a cargarse un vez los elementos de la lista y ya no se van a modificar más mientras el usuario interaccione con la lista; si queremos añadir o eliminar elementos mientras el usuario toca la lista, requerimos de otro tipo de adaptador (Puedes aprender como utiliza inflate() el método getView() del Adapter en este otro tutorial).

Código de la clase “Lista_adaptador.java”:

package jarroba.ramon.listado;

import java.util.ArrayList;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

/** Adaptador de ListView universal, para www.jarroba.com
 * @author Ramon Invarato Menéndez
 */
public abstract class Lista_adaptador extends BaseAdapter {

    private ArrayList<?> entradas; 
    private int R_layout_IdView; 
    private Context contexto;

    public Lista_adaptador(Context contexto, int R_layout_IdView, ArrayList<?> entradas) {
        super();
        this.contexto = contexto;
        this.entradas = entradas; 
        this.R_layout_IdView = R_layout_IdView; 
    }

    @Override
    public View getView(int posicion, View view, ViewGroup pariente) {
        if (view == null) {
	    LayoutInflater vi = (LayoutInflater) contexto.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
            view = vi.inflate(R_layout_IdView, null); 
        }
        onEntrada (entradas.get(posicion), view);
        return view; 
    }

    @Override
    public int getCount() {
        return entradas.size();
    }

    @Override
    public Object getItem(int posicion) {
        return entradas.get(posicion);
    }

    @Override
    public long getItemId(int posicion) {
        return posicion;
    }

    /** Devuelve cada una de las entradas con cada una de las vistas a la que debe de ser asociada
     * @param entrada La entrada que será la asociada a la view. La entrada es del tipo del paquete/handler
     * @param view View particular que contendrá los datos del paquete/handler
     */
    public abstract void onEntrada (Object entrada, View view);

}

Este código lo que hace es crear un adaptador para ListView. En el constructor hay que pasarle el contexto de la aplicación, el id del layout de la entrada (en este ejemplo “R.layout.entrada”), y el ArrayList que construimos anteriormente con los handler con los datos. Como es obvio, ya que pide los datos del ArrayList, este código irá justo después de la creación del ArrayList. Al crear el objeto se nos pedirá sobrescribir el método “onEntrada”, que será donde asignaremos cada parte del handler de la clase “Lista_entrada.java” a cada una de las copias de las vistas “entrada.xml”. “onEntrada” da de información: el objeto con solo los datos de la entrada que va a construir y la vista donde lo va a meter. Te sorprenderá el escaso código que hay que usar y lo simple que es su uso, a continuación lo veremos.

Una vista rápida de donde se usa este adaptador.

Partes de un ListView de Android - www.jarroba.com

En el ejemplo lo situaremos dentro del “MainActivity.java” en el “onCreate”, después del código que ya había (Nota: como comentamos anteriormente, al final publicaremos el código completo). Código para usar el adaptador:

ListView lista = (ListView) findViewById(R.id.ListView_listado);
        lista.setAdapter(new Lista_adaptador(this, R.layout.entrada, datos){
			@Override
			public void onEntrada(Object entrada, View view) {
		            TextView texto_superior_entrada = (TextView) view.findViewById(R.id.textView_superior); 
		            texto_superior_entrada.setText(((Lista_entrada) entrada).get_textoEncima()); 

		            TextView texto_inferior_entrada = (TextView) view.findViewById(R.id.textView_inferior); 
		            texto_inferior_entrada.setText(((Lista_entrada) entrada).get_textoDebajo()); 

		            ImageView imagen_entrada = (ImageView) view.findViewById(R.id.imageView_imagen); 
		            imagen_entrada.setImageResource(((Lista_entrada) entrada).get_idImagen());
			}
		});

Este poco de código usa el adaptador. Se asigna cada View con su dato en el momento justo en el que se construye cada entrada ¿No dije que era fácil?.

Ya solo queda capturar el evento de Click para cada una de las entradas y hacer lo que sea con esta. En este ejemplo recogemos la descripción y la mostramos en un Toast. Esto lo hacemos al devolver el adaptador y conociendo la posición nos habrá devuelto la entrada pulsada. Después del anterior código escribimos el escuchador del evento click como se hace normalmente:

lista.setOnItemClickListener(new OnItemClickListener() { 
    @Override
    public void onItemClick(AdapterView<?> pariente, View view, int posicion, long id) {
        Lista_entrada elegido = (Lista_entrada) pariente.getItemAtPosition(posicion); 

        CharSequence texto = "Seleccionado: " + elegido.get_textoDebajo();
        Toast toast = Toast.makeText(MainActivity.this, texto, Toast.LENGTH_LONG);
        toast.show();
    }
 });

Y ya al fin, el código completo del “MainActivity.java”, es el siguiente:

package jarroba.ramon.listado;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

	private ListView lista; 

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

        ArrayList<Lista_entrada> datos = new ArrayList<Lista_entrada>();  

        datos.add(new Lista_entrada(R.drawable.im_buho, "BUHO", "Búho es el nombre común de aves de la familia Strigidae, del orden de las estrigiformes o aves rapaces nocturnas. Habitualmente designa especies que, a diferencia de las lechuzas, tienen plumas alzadas que parecen orejas."));
        datos.add(new Lista_entrada(R.drawable.im_colibri, "COLIBRÍ", "Los troquilinos (Trochilinae) son una subfamilia de aves apodiformes de la familia Trochilidae, conocidas vulgarmente como colibríes, quindes, tucusitos, picaflores, chupamirtos, chuparrosas, huichichiquis (idioma nahuatl), mainumby (idioma guaraní) o guanumby. Conjuntamente con las ermitas, que pertenecen a la subfamilia Phaethornithinae, conforman la familia Trochilidae que, en la sistemática de Charles Sibley, se clasifica en un orden propio: Trochiliformes, independiente de los vencejos del orden Apodiformes. La subfamilia Trochilinae incluye más de 100 géneros que comprenden un total de 330 a 340 especies."));
        datos.add(new Lista_entrada(R.drawable.im_cuervo, "CUERVO", "El cuervo común (Corvus corax) es una especie de ave paseriforme de la familia de los córvidos (Corvidae). Presente en todo el hemisferio septentrional, es la especie de córvido con la mayor superficie de distribución. Con el cuervo de pico grueso, es el mayor de los córvidos y probablemente la paseriforme más pesada; en su madurez, el cuervo común mide entre 52 y 69 centímetros de longitud y su peso varía de 0,69 a 1,7 kilogramos. Los cuervos comunes viven generalmente de 10 a 15 años pero algunos individuos han vivido 40 años. Los juveniles pueden desplazarse en grupos pero las parejas ya formadas permanecen juntas toda su vida, cada pareja defendiendo un territorio. Existen 8 subespecies conocidas que se diferencian muy poco aparentemente, aunque estudios recientes hayan demostrado diferencias genéticas significativas entre las poblaciones de distintas regiones."));
        datos.add(new Lista_entrada(R.drawable.im_flamenco, "FLAMENCO", "Los fenicopteriformes (Phoenicopteriformes), los cuales reciben el nombre vulgar de flamencos, son un orden de aves neognatas, con un único género viviente: Phoenicopterus. Son aves que se distribuyen tanto por el hemisferio occidental como por el hemisferio oriental: existen cuatro especies en América y dos en el Viejo Mundo. Tienen cráneo desmognato holorrino, con 16 a 20 vértebras cervicales y pies anisodáctilos."));
        datos.add(new Lista_entrada(R.drawable.im_kiwi, "KIWI", "Los kiwis (Apterix, gr. 'sin alas') son un género de aves paleognatas compuesto por cinco especies endémicas de Nueva Zelanda.1 2 Son aves no voladoras pequeñas, aproximadamente del tamaño de una gallina. Antes de la llegada de los humanos alrededor del año 1300, en Nueva Zelanda los únicos mamíferos que había eran murciélagos, y los nichos ecológicos que en otras partes del mundo eran ocupados por animales tan diversos como caballos, lobos y ratones fueron utilizados en Nueva Zelanda por pájaros (y en menor proporción por ciertas especies de reptiles). La denominación kiwi es maorí, idioma del pueblo homónimo de linaje malayopolinesio que colonizó Nueva Zelanda antes de la llegada de los europeos."));
        datos.add(new Lista_entrada(R.drawable.im_loro, "LORO", "Las Psitácidas (Psittacidae) son una familia de aves psitaciformes llamadas comúnmente loros o papagayos, e incluye a los guacamayos, las cotorras, los periquitos, los agapornis y formas afines."));
        datos.add(new Lista_entrada(R.drawable.im_pavo, "PAVO", "Pavo es un género de aves galliformes de la familia Phasianidae, que incluye dos especies, el pavo real común (Pavo cristatus) y el pavo real cuelliverde (Pavo muticus).1"));
        datos.add(new Lista_entrada(R.drawable.im_pinguino, "PINGÜINO", "Los pingüinos (familia Spheniscidae, orden Sphenisciformes) son un grupo de aves marinas, no voladoras, que se distribuyen únicamente en el Hemisferio Sur, sobre todo en sus altas latitudes."));

        lista = (ListView) findViewById(R.id.ListView_listado);
        lista.setAdapter(new Lista_adaptador(this, R.layout.entrada, datos){
			@Override
			public void onEntrada(Object entrada, View view) {
		        if (entrada != null) {
		            TextView texto_superior_entrada = (TextView) view.findViewById(R.id.textView_superior); 
		            if (texto_superior_entrada != null) 
		            	texto_superior_entrada.setText(((Lista_entrada) entrada).get_textoEncima()); 

		            TextView texto_inferior_entrada = (TextView) view.findViewById(R.id.textView_inferior); 
		            if (texto_inferior_entrada != null)
		            	texto_inferior_entrada.setText(((Lista_entrada) entrada).get_textoDebajo()); 

		            ImageView imagen_entrada = (ImageView) view.findViewById(R.id.imageView_imagen); 
		            if (imagen_entrada != null)
		            	imagen_entrada.setImageResource(((Lista_entrada) entrada).get_idImagen());
		        }
			}
		});

        lista.setOnItemClickListener(new OnItemClickListener() { 
			@Override
			public void onItemClick(AdapterView<?> pariente, View view, int posicion, long id) {
				Lista_entrada elegido = (Lista_entrada) pariente.getItemAtPosition(posicion); 

                CharSequence texto = "Seleccionado: " + elegido.get_textoDebajo();
                Toast toast = Toast.makeText(MainActivity.this, texto, Toast.LENGTH_LONG);
                toast.show();
			}
        });

    }

}

Esperamos que haya sido aclaratorio y para entender muchas cosas sobre cómo se construye una lista.

Aquí dejo para descargar el proyecto entero: Listado

En respuesta a las preguntas más comunes de nuestros lectores. Si quieres hacer otra cosa con los listados, así como si has visto cosas que no has sabido como solucionar; e incluso, con lo aquí aprendido, como hacer un GridView o un Spinner completamente personalizados. Te recomiendo que eches una ojeada al artículo que expande los conocimientos de ListView, se solventan muchas dudas y enseña mucho más, en: http://jarroba.com/expansion-listview/

También puede ser muy interesante el artículo sobre programar para diferentes dispositivos Android con la arquitectura de Fragments, en el que extiendo un poco más el ejemplo de listado y añado conceptos avanzados.

Comparte esta entrada en:
Safe Creative #1401310112503
ListView o listado en Android por "www.jarroba.com" esta bajo una licencia Creative Commons
Reconocimiento-NoComercial-CompartirIgual 3.0 Unported License.
Creado a partir de la obra en www.jarroba.com

402 comentarios en “ListView o listado en Android”

  1. Me ha encantado el articulo. Las explicciones. Todo, muy bien explicado. Felicidadess! y Gracias. Como soy nueva con esto si en un futuro puedo aportar algo, lo haré seguro 🙂

  2. Buenas noches Ramón, muchas gracias por el tutorial, me ha sido de gran ayuda como todo el contenido que encuentro en esta página. Por curiosidad, ahora conozco como trasladar el contenido de un array a un listview pero, y al contrario? Es decir, cómo puedo trasladar los clics de un listview a un array para, por ejermplo, imprimir en otro layout las opciones elegidas?

     

    Espero haberme explicado correctamente. De nuevo enhorabuena por el tutorial.

    1. Hola Javier, nos alegra que te haya servido el tutorial 🙂

      Existen varios modos, dependiendo un poco de la profundidad que necesites. Puedes modificar el Adapter para que guarde lo que necesites, en la propia Activity, o creo que lo que necesitas es guardar datos. Para guardar datos y pasarlos a otro sitios existen varios métodos, tienes ejemplos completos en nuestro libro gratuito de Android en: http://jarroba.com/libro-android-100-gratis/

  3. Hola estoy haciendo un proyecto pararesido al tuyo pero me sale un error en el codigo de los string queriia saber como ser un string para este codigo.

    si puedes porfavor y grcaias

  4. Exelente aporte, muchisimas gracias, en el post dices que para agregar o eliminar items del listView hay que utilizar otro adaptador, podrias haceme el favor de darme un idea de como seria ese adaptador para poder agregar y eliminar items a medida que el usuario interactua con la app?

    te agradezco mucho.

    1. Hola Cristian. Hay que modificar el Adaptador que hay aquí. Hay que añadir bastante código, pero la idea es tener o eliminar el en Array del Adaptador las filas y luego redibujarlas. Principalmente tienes que utilizar:

      int index_a_eliminar = 100;

      mi_array_list.remove(index_a_eliminar);

      this.mi_adaptador.notifyDataSetChanged();

      1. Gracias por responder, me ayudó mucho. Tengo otra duda, estoy tratando de acceder a lo que hay en cada item, es decir, necesito que cuando el usuario le de click a un item mostrat un Toast con el nombre del animal, por ejemplo. Pero no logro hacerlo.
         ¿Como seria la forma correcta de hacerlo? Gracias.

  5. Hola Ramón, gracias por compartir tu conocimiento con todos nosotros, tengo la siguiente duda, tengo un RecyclerView en el cual cuento con una información como es id, nombre, descripcion, entre otros, y adicionalmente esta incluido un Spinner con unos valores determinados y quiero guardar todos los valores en una base de datos remota y que cuando ingrese nuevamente en la aplicación y cuando cargue la actividad se muestre el valor del spinner seleccionado en una primera instancia por el usuario.

    Si me pudieras ayudar te lo agradecería, estos son los métodos que estoy usando.

    "ESTE ES MI ACTIVIDAD java"

    Pedidos clase pública se extiende AppCompatActivity implementa OnItemSelectedListener {

    Contexto mainContext;
    managerPedidos DatabaseManager privadas;
    reciclador RecyclerView privada;
    lManager RecyclerView.LayoutManager privada;
    Lista <orden> ListItems privadas;

    @Anular
    protected void onCreate (Bundle savedInstanceState) {
    super.onCreate (savedInstanceState);
    setContentView (R.layout.activity_pedidos);
    MultiDex.install (this);

    });

    managerOrders = new DatabaseManager (este);
    ListItems = managerOrders.getOrderList ();

    reciclador = (RecyclerView) findViewById (R.id.orders);
    recycler.setHasFixedSize (true);

    lManager = new LinearLayoutManager (este);
    recycler.setLayoutManager (lManager);

    ProductoAdapter adaptador = new ProductoAdapter (ListItems, este);
    recycler.setAdapter (adaptador);
    recycler.setItemAnimator (nueva DefaultItemAnimator ());

    }

    @Anular
    protegida OnDestroy void () {
    managerPedidos.cerrar ();
    super.onDestroy ();
    }

    }

    "Este es mi ayudante"

    DbHelper clase pública se extiende SQLiteOpenHelper {

    DB_NAME static final String privada = "vetStore.sqlite";
    privado static final int VERSION = 1;

    DbHelper pública (contexto Contexto) {
    super (contexto, DB_NOMBRE, null, versión);
    }

    @Anular
    public void onCreate (SQLiteDatabase db) {
    tratar {
    db.execSQL (DataBaseManager.CREATE_TABLE_ORDER);

    } Catch (SQLException e)
    {E.getMessage ();
    }
    }

    @Anular
    pública ONUPGRADE vacío (SQLiteDatabase db, int OldVersion, int newVersion) {

    db.execSQL ( "DROP TABLE IF EXISTS" + DataBaseManager.TABLE_ORDER);
    onCreate (db);

    }
    }

    "ESTE ES MI DatabaseManager:"

    DatabaseManager public class {

    pública TABLE_ORDER static final String = "orden";
    pública CREATE_TABLE_ORDER static final String = "CREATE TABLE" + TABLE_ORDER + "(" +
    "Id número entero," + // 0
    "Texto no puede," + 1 //
    "Texto nombre," + // 2
    "Descripción de texto," + // 3
    "Entero Price," + // 4
    "Texto tienName," + // 5
    "Imagen de texto)"; // 6

    ayudante DbHelper privada;
    db SQLiteDatabase privada;

    DatabaseManager pública (contexto Contexto) {
    ayudante = new DbHelper (contexto);
    db = helper.getWritableDatabase ();
    db = helper.getReadableDatabase ();
    }

    public void cerrado () {
    si (db.isOpen ())
    db.close ();
    }

    ContentValues ​​generateContentValues ​​privadas (int id, Cadena no puede, Nombre de la cadena, la cadena Descripción,
    int precio, Cadena tienName, Cadena Imagen)
    {
    ContentValues ​​CV = nuevos ContentValues ​​();
    cv.put ( "Id", Id);
    cv.put ( "canto", de peralte);
    cv.put ( "Nombre", nombre);
    cv.put ( "Descripción", descripción);
    cv.put ( "Precio", precio);
    cv.put ( "tienName", tienName);
    cv.put ( "Imagen", Imagen);
    cv regresar;
    }

    pública inserto void (int id, no puede Cadena, Cadena de nombre, la cadena Descripción int precio, Cadena tienName, Cadena Imagen) {
    db.insert (TABLE_ORDER, null, generateContentValues ​​(ID, no puede, nombre, descripción, precio, tienName, Imagen));
    }

    updateValues ​​public void (int id, Cadena Newcant, nombre de la cadena, cadena de descripción, int Precio, Cadena tienName, Cadena Imagen) {

    SQLiteDatabase db = helper.getWritableDatabase ();

    if (! db = null) {

    db.update (TABLE_ORDER, generateContentValues ​​Id, Newcant, nombre, descripción, precio, tienName, Imagen), "Id =?", new String [] {String.valueOf (Id)});
    db.close ();
    }
    }

    Lista pública <orden> getOrderList () {

    Lista <orden> order = new ArrayList <orden> ();
    la selección String = "SELECT * FROM" + TABLE_ORDER;
    SQLiteDatabase db = helper.getReadableDatabase ();
    Cursor Cursor = db.rawQuery (selección, null);

    si (cursor.moveToFirst ()) {
    do {
    order.add (nueva Orden (cursor.getInt (0), cursor.getString (1), cursor.getString (2),
    cursor.getString (3), cursor.getInt (4), cursor.getString (5), cursor.getString (6)));
    } While (cursor.moveToNext ());
    }
    cursor.close ();
    db.close ();

    Para volver;
    }

    OpenDB public void () {
    tratar {
    db = helper.getWritableDatabase ();
    db = helper.getReadableDatabase ();
    } Catch (SQLException e) {
    e.printStackTrace ();
    }
    }
    }

    Y esta es mi adaptador:

    ProductAdapter clase pública se extiende RecyclerView.Adapter <productadapter.productviewholder> {

    imageLoader ImageLoader privada;
    Selección Selección privado;
    Contexto mainContext;
    db DatabaseManager;
    El canto de cadena, newCant;

    Lista <orden> artículos;

    ProductAdapter pública (List <orden> artículos, context contexto) {
    súper();
    this.items = artículos;
    this.mainContext = contexto;
    }

    @Anular
    pública ProductViewHolder onCreateViewHolder (ViewGroup matriz, int ViewType) {
    Ver v = LayoutInflater.from (parent.getContext ())
    .inflate (R.layout.show_order, padre, false);
    ProductViewHolder pHolder = new ProductViewHolder (v);
    volver pHolder;
    }

    @Anular
    pública onBindViewHolder vacío (última ProductViewHolder viewHolder, posición int) {
    artículo del producto = items.get (posición);

    imageLoader = CustomVolleyRequest.getInstance (mainContext) .getImageLoader ();

    viewHolder.txtId.setText (String.valueOf (item.getId ()));
    viewHolder.img.setImageUrl (item.getimg (), imageLoader);
    viewHolder.txtname.setText (item.getname ());
    viewHolder.txtdescrip.setText (item.getDescription ());
    viewHolder.txtprice.setText (String.valueOf (item.getPrice ()));
    viewHolder.txtcliNam.setText (item.getTienName ());

    viewHolder.txtcant.setAdapter (a ());

    viewHolder.txtcant.setOnItemSelectedListener (nueva AdapterView.OnItemSelectedListener () {
    @Anular
    public void onItemSelected (padre AdapterView, vista, posición int, long id) {

    newCant = parent.getItemAtPosition (posición) .toString ();

    }

    @Anular
    public void onNothingSelected (AdapterView padre) {

    }
    });
    }

    SpinnerAdapter privada a () {

    String [] order = new String [] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"} ;

    ArrayAdapter <cadena> adaptador = new ArrayAdapter <> (mainContext, android.R.layout.simple_spinner_item, prder);

    adapter.setDropDownViewResource (android.R.layout.simple_spinner_dropdown_item);

    adaptador de retorno;
    }

    updateValues ​​public void (int id, Cadena Newcant, nombre de la cadena, cadena de descripción, int Precio, Cadena tienName, Cadena Imagen) {

    DatabaseManager DBManager = new DatabaseManager (mainContext);

    dbManager.updateValues ​​(Id, Newcant, nombre, descripción, precio, tienName, Imagen);

    }
    }

    @Anular
    public int getItemCount () {
    items.size volver ();
    }

    OrderViewHolder clase extiende RecyclerView.ViewHolder implementa View.OnClickListener {

    txtID TextView pública;
    img NetworkImageView pública;
    txtName TextView pública;
    txtdescrip TextView pública;
    txtprice TextView pública;
    txtcant Spinner;
    txtcliNam TextView pública;

    ProductoViewHolder pública (Ver v) {
    super (v);
    txtID = (TextView) v.findViewById (R.id.Id);
    img = (NetworkImageView) v.findViewById (R.id.Imagen);
    txtName = (TextView) v.findViewById (R.id.txtName);
    txtdescrip = (TextView) v.findViewById (R.id.txtVDescription);
    txtprice = (TextView) v.findViewById (R.id.price);
    txtcliNam = (TextView) v.findViewById (R.id.tVCliName);
    txtcant = (Spinner) v.findViewById (R.id.cant);

    }
    }
    }

    Agradezco toda la ayuda que me puedan dar, no puedo encontrar la solución a lo que necesito, gracias.

    1. Hola Mario, entiendo que cada elemento de tu listado tiene un Spinner. Puedes guardar su estado con el ID del elemento en la base de datos (en otra de estados si quieres separar de la de datos), para posteriormente volver a cargar el elemento en la posición en la que se encontraba cuando vuelvas a cargar la Activity (lees todos los estados de la base de datos y los actualizas en cada Spinner)

  6. Hola Ramon, muchisimas gracias por este tutorial y por todos los que nos dejas!!
    Tengo una duda, como puedo hacer para abrir este código en Android Studio? Existe una versión para Android Stud?

    Muchas Gracias!! Espero tu respuesta

  7. Hola Ramon, primeramente permiteme felicitarte por tus tutoriales son muy buenos me han ayudado mucho, te escribo porque necesito que me ayudes con  una lista de datos numericos con un boton y dos texView; esto se utilizaria de la siguiente manera al seleccionar uno de los datos de la lista, presiono el boton el mismo que me mostrara en uno de los texView los numeros pares sumados hasta dicho numero y en el otro texView los numeros impares multiplicados hasta dicho numero. No soy muy practica en las listas he investigado y hay que crear arreglo pero no se como aplicarlos, de ante mano te agradezco por la atencion que le des a mi comentario,, aqui te dejo mi codigo,

    esto es lo que tengo :

    package com.example.editajohana.vectores;

    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.ListView;

    public class EJERCICIO extends AppCompatActivity
    {
    ListView lb;
    Integer[] numeros = {
    1, 2, 3, 4, 5,
    6, 7, 8, 9, 10};
    @Override

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_ejercicio);
    lb = (ListView) findViewById(R.id.lb);

    }
    }

    1. Hola María. No entiendo muy bien lo que necestias. Si necesitas los número pares o impares hasta cierto número lo puedes sacar con el módulo 2. Por ejemplo para saber si 5 es par o impar puedes hacer: “5 % 2 = 1”, como es 1 sabrás que es impar, si es 0 es par

  8. Hola Ramón. 

    Tengo una lista simple con x elementos (muchos). Se trata de un diccionario enorme. Pero lo que yo quiero es que cuando reinicie el app (que es eso, una lisma simple con muchos elementos) me aparezca a partir del último elemento al que he hecho clic y no desde el primer elemento ¿Cómo puedo guardar el elemento deseado para volver después a él? Muchas gracias por tu tiempo. 

    1. Lo mejor es que guardes el id del elemento y luego cargues el listado dirigiendo al usuario a tal elemento. Puedes utilizar para ello el método de ListView: setSelection(posicion)

  9. Buen día

    Ya logré llenar mis listas, el problema que tengo ahora es que no logro hacerlas clikeables, me dice que no se puede hacer el cast. Dejo aqui las líneas del código que tengo para llenar la lista y donde intento hacerla clikeable, esto lo tengo como un metodo al cual llamo en el onCreate de la actividad. Puedes asesorarme al respecto?

    DataBase db = new DataBase(this);
    String Consulta = "SELECT "+TablasBD.ESTUDIOS_ELECTRICOS_ID+" as _id, "+TablasBD.ESTUDIOS_ELECTRICOS_ID_CLIENTE+", "+TablasBD.ESTUDIOS_ELECTRICOS_NOMBRE+", "+TablasBD.ESTUDIOS_ELECTRICOS_FECHA+" FROM "+ TablasBD.ESTUDIOS_ELECTRICOS;
    SQLiteDatabase admin = db.getReadableDatabase();
    final Cursor cursor = admin.rawQuery(Consulta,null);
    ListEstudios = (ListView) findViewById(R.id.lst_Estudios);
    final String [] columnas = {TablasBD.ESTUDIOS_ELECTRICOS_NOMBRE,TablasBD.ESTUDIOS_ELECTRICOS_FECHA};
    int [] views = {R.id.tv_card_list_estudios_Nombre,R.id.tv_card_list_estudios_Cliente};
    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,R.layout.card_lista_estudios,cursor,columnas,views,0);
    ListEstudios.setAdapter(adapter);

    ListEstudios.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    EstudiosElectricos elegido = (EstudiosElectricos)(parent.getItemAtPosition(position));
    Toast.makeText(ListaEstudios.this,"Iniciando detalle del estudio "+elegido.getNombre(),Toast.LENGTH_SHORT).show();
    /* Intent intent = new Intent(ListaEstudios.this, DetalleEstudio.class);
    intent.putExtra("NombreEstudio",elegido.getNombre());
    intent.putExtra("IdEstudio",elegido.getIdEstudio());
    startActivity(intent);*/
    }
    });

    db.close();

    1. Lo veo bien el código. Comprueba que la clase “EstudiosElectricos” tengan bien el formato y esté importada correctamente.

        1. Me refería a que la clase que está siendo casteada esté construida correctamente, sino podría dar problemas de casteo.

  10. Buen día, Tengo un ListView con datos que provienen de una base de datos en el movil y quiero hacer que la lista sea clikeable, pero no consigo hacerlo…puedes asesorarme?

    Este es el código que utilizo para llenar la lista…

    lst_proyectos = (ListView) findViewById(R.id.lts_proyectos);
    BaseDatos admin = new BaseDatos(this);
    SQLiteDatabase db = admin.getReadableDatabase();
    final Cursor cursor = db.rawQuery("select id AS _id, NombreEstudio from TablaEstudios",null);
    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item,cursor,new String[]{"NombreEstudio"}, new int[]{android.R.id.text1});
    adapter.setDropDownViewResource(android.R.layout.simple_list_item_1);
    lst_proyectos.setAdapter(adapter);

  11. Mi mas sincera enhorabuena por tu dedicacion y trabajo. Verdaderamente, tienes un  don especial para explicar conceptos "dificiles".

    Muchas gracias,,,,, os seguire de cerca.

     

  12. Hola ramon necesito de su ayuda..estoy pasando un objeto parcelable a una segunda actividad en mi segunda actividad logro visualizar lo que contiene mi objeto Arraylist con un System out. printl("datos"+Arrayfruta) y lo estoy recibiendo de esta manera Arrayfruta= (ArrayList<Clasefruta>) getIntent().getExtras().get("Arreglofruta");,

    de mi segunda actividad intento listar el contenido de Arrayfruta en un reciclerView el reciclerview tiene su adaptador(Crie una clase adaptador en donde estoy intentando manadar el contenido del objeto) ahora intento pasar en contenido de Arrayfruta al adaptador pero no lo e conseguido alguna idea de como resolver este problemita… saludos espero su pronta respuesta

     

  13. buenos dias alguien me  puede ayudar con la codificacion, me piden ingresar un numero menor y un numero mayor

    de lo cual se debe de guardar en un listView en intervalo de esdo 2 numeros. como lo haria para que se guarde

    1. Simplemente con unos ifs comprueba si el número es mayor o menor qué para poder guardarlos en el ListView que necesites 🙂

  14. hola ramon tu ejemplo es muy bueno nada mas que no pude adaptar el adaptador ya que tu manejas  ArrayList<Listado_entrada> datos = new ArrayList<Listado_entrada>();  y yo manejo esto Clientes [] listaclientes y el error me sale aqui  el arrayadapter por que le pasas el array

    yop le pase el strin y me marca error en el get(position) espero me puedas ayudar 

      

    /Tarea Asíncrona para llamar al WS de consulta en segundo plano
            private class TareaWSConsulta extends AsyncTask<String,Integer,Boolean> {
                
                 Cliente[] listaClientes;
                 //ArrayList<Clienteadaptador> datos = new ArrayList<Clienteadaptador>(); 
                 
                protected Boolean doInBackground(String… params) {
                    
                    boolean resul = true;
             
                    final String NAMESPACE = "http://xxxxxxx.org/&quot;;
                    final String URL="http://www.xxxxxxxx.somee.com/Servicioclientes.asmx&quot;;
                    final String METHOD_NAME = "ListadotraficoSOMEE";
                    final String SOAP_ACTION = "http://xxxxxxxxx.org/ListadotraficoSOMEE&quot;;

                    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
                    request.addProperty("nombre", txtNombre.getText().toString()); 
                    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
                    envelope.dotNet = true;

                    envelope.setOutputSoapObject(request);

                    HttpTransportSE transporte = new HttpTransportSE(URL);

                    try 
                    {
                        transporte.call(SOAP_ACTION, envelope);

                        SoapObject resSoap =(SoapObject)envelope.getResponse();
                        
                        listaClientes = new  Cliente[resSoap.getPropertyCount()];
                        
                        for (int i = 0; i < listaClientes.length; i++) 
                        {
                               SoapObject ic = (SoapObject)resSoap.getProperty(i);
                                
                               Cliente cli = new Cliente();
                               cli.id = Integer.parseInt(ic.getProperty(0).toString());
                               cli.nombre = ic.getProperty(1).toString();
                             //  cli.telefono = ic.getProperty(2).toString();
                                
                               listaClientes[i] = cli;
                              
                        }
                    } 
                    catch (Exception e) 
                    {
                        resul = false;
                    } 
             
                    return resul;
                }
                
                protected void onPostExecute(Boolean result) {
                    
                    if (result)
                    {
                        
                                            //Rellenamos la lista con los nombres de los clientes
                        final String[] datos = new String[listaClientes.length];
                         
                        for(int i=0; i<listaClientes.length; i++)
                             datos[i] = listaClientes[i].nombre+listaClientes[i].telefono;
                        
                                          yo lo adapto aasy y llena la lista pero la quiero ordenar como tu ejemplo nomas que no puedo       
                        ArrayAdapter<String> adaptador =
                            new ArrayAdapter<String>(Activity_lista.this,
                                android.R.layout.simple_list_item_1, datos);
                         
                
                        
                        
                        
                    }
                    else
                    {
                        txtResultado.setText("Error!");
                    }
                }

  15. Exceltente post todo explicado muy bien, una pregunta como podria implementar la busqueda con el addTextChangedListener si no esta alguna variable adapter donde pueda usarlo . agradesco tu resuesta gracias

    1. Si tienes un EditText en cada fila que quieres escuchar cambios con addTextChangedListener, en este ejemplo lo podrías poner en el onEntrada buscando la referencia al Edittext (o en el Adapter en el getView)

      1. hola ramon, gracias por info, por fa me puedes ayudar en esto, bueno, supongamos que ya tengo la lista creada, y en todas esas puse un checkbox, ahora quiero que todos lo que los checkee, se muden a otra lista

        1. Existen varias maneras, por ejemplo, puedes guardar los ids de los elementos pulsados en un ArrayList y luego recuperarlo en la otra lista.

  16. Hola, interesantisimo post y la verdad es que me sirvio de muchisimo para entender todo este tema de los adaptadores en las listas, que me tenia la cabeza dando vueltas hace dias… Millones de gracias por el tutorial, y definitivamente voy a leerme el libro. Tengo, de todas maneras, una problematica ligeramente diferente, y es que necesito mostrar Un GridView o un TableLayout diferente en cada item de una lista expandible. Pudieras por favor ayudarme con este tema, o sugerirme alguna forma de hacerlo si es que es posible. Gracias de antemano por la ayuda y por el tiempo. Mis saludos y mis respetos!

  17. Saludos, adjunto imagenes con respecto a la problematica anterior para su mayor comprension:

    supongamos que tengo un Activity (llamemoslo recibe.xml) con tres textView: TextView1 TextView2

    ¿Como se haria para pasar el elementos del Lista_entrada (titulo y el contenido) a ese nuevo activity?

    Por ejemplo al hacer click en el renglon BUHO desde el MainActivity, se reciba en el activity Recibe de la siguente manera: en TextView1 se imprima BUHO y en TextView2 se imprima "Búho es el nombre común de aves de la familia Strigidae, del …etc"

    1. Para hacer lo que necesitas se hace desde el OnItemClickListener (tienes información sobre como trabajan los eventos en nuestro libro gratuito http://jarroba.com/libro-android-100-gratis/), luego mediante almacenamiento de datos (más información en http://developer.android.com/intl/es/guide/topics/data/data-storage.html), Singleton o como está hecho el artículo con eventos. 

      Para enviárnos imágenes puedes hacerlo desde nuestro foro en http://jarroba.com/foro/

  18. Hola, muy buena explicacion. Baje el proyecto y corre muy bien.

    Solo un detalle por curiosidad, supongamos que tengo un Activity (llamemoslo recibe.xml) con tres textView: TextView1 TextView2

    ¿Como se haria para pasar el elementos del Lista_entrada (titulo y el contenido) a ese nuevo activity?

    Por ejemplo al hacer click en el renglon BUHO desde el MainActivity, se reciba en el activity Recibe de la siguente manera: en TextView1 se imprima BUHO y en TextView2 se imprima "Búho es el nombre común de aves de la familia Strigidae, del …etc"

    Lo he intentado de esta manera, pero al hacer click en cualquier elemento se cierra la aplicacion:

    /***************************************************en MainActivity.java***********************************************/

            final Bundle bund = this.getIntent().getExtras();       

    lista.setOnItemClickListener(new OnItemClickListener() { 
                @Override
                public void onItemClick(AdapterView<?> pariente, View view, int posicion, long id) {
                    Lista_entrada elegido = (Lista_entrada) pariente.getItemAtPosition(posicion); 
                    
                    CharSequence texto = "Seleccionado: " + elegido.get_textoDebajo();
                    Toast toast = Toast.makeText(MainActivity.this, texto, Toast.LENGTH_LONG);
                    toast.show();
                    /**************************************************/
                    //Intent intentEnviaPedido = new Intent(OrdenNueva.this, Pedido.class);
                    Intent intentEnviaPedido = new Intent(getApplicationContext(), Recibe.class);
                    
                    //final Bundle bund2 = getIntent().getExtras();
                    
                    bund.putString("1", (String) texto);
                    bund.putString("2", (String) texto);
                    
                    //bund2.putBundle("NumPedido", (Bundle) valor);
                    
                    intentEnviaPedido.putExtras(bund);
                    //intentEnviaPedido.putExtras(bund2);
                    
                    //Intent ii = new Intent(getApplicationContext(), Pablo.class);//toda la fila lleva  la clase
                    /**************************************************/
                }
            });

    /******************************************CLASE RECIBE.JAVA*************************************************************************/

    public class Recibe extends Activity{
        
        private TextView tv1;private TextView tv2;private TextView tv3;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.recibe );
            
            tv1=(TextView) findViewById(R.id.textView1);
            tv2=(TextView) findViewById(R.id.textView2);

            Bundle bund=getIntent().getExtras();
            tv1.setText(bund.getString("1"));
            tv2.setText(bund.getString("2"));

        }
    }

    /*******************************************ACTIVITY recibe.xml************************************************/

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&quot;
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <LinearLayout
            android:layout_width="110dp"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="TextView" />

            <TextView
                android:id="@+id/textView2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="TextView" />

        </LinearLayout>

    </LinearLayout>

    /*****************************************************************************************************************/

     

    ¿Que le sobra o le falta para que funcione…?

     

  19. Muy buen tutorial Amigo y todos los que haces, en particular tengo una duda con sobre esto y la cual es si en el archivo entrada.xml podria ir un edittext o incluso un spiner? para poder tener una lista de edittext infinitos dependiendo de la lista?

  20. Hola buenas, primero que nada decir que da gusto ver que hay gente como vosotros que comparte todos estos conocimientos y el tiempo que imagino que le dedicais a esto , que se nota que es lo vuestro.

    Mi duda esta en la Clase Lista_adaptador, no acabado de entender porque se llama al metodo abstracto onEntrada dentro de el metodo getview.

     

    public View getView(int posicion, View view, ViewGroup pariente) {
    if (view == null) {
    LayoutInflater vi = (LayoutInflater) contexto.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    view = vi.inflate(R_layout_IdView, null);
    }
    onEntrada (entradas.get(posicion), view);
    return view;

    1. Hola Carlos. Gracias por los ánimos 🙂

      No es necesario que crees el método onEntrada() dentro del getview(), puedes poner ahí las views directamente dentro del getView() y prescindir del onEntrada(); aunque de este modo tendrías que hacer un Adapter para cada listado de tu aplicación, el de este ejemplo está diseñado para reutilizarlo. Simplemente en este artículo lo explico así para intentar hacer un Adaptador genérico lo más fácil posible para la mayoría de listados complejos (y simples si es necesario, aunque para simples es mejor este otro artículo que usa menos código) y lo más reutilizable posible para escribir cuanto menos código mejor 😉

  21. Que buen post chicos, muy bien explicado!!

    Solo que tengo una duda.

    Estoy haciendo una app con ListView pero en el XML entrada unicamente defino TextView(Nombres, Apellidos, correo, direccion, telefono), pero sucede que al momento de mostrar la lista solo me muestra el ultimo dato ingresado y los demas solo me muestra las etiquetas que le he definidio en el XML entrada("nombres", "apellidos", "correo", "direccion", "telefono"). He verificado la clase Adaptador, MainActivity y el diseño del XML entrada, pero lo tengo igual que el ejemplo.

     

    Ayuda por favor, como puedo solucionar para que me muestre todos los registros en el ListView

    1. Hola. Sin el código es un poco complicado. Comprueba como se están asignando las Views (en el ejemplo en onEntrada)

  22. Hola Ramon, me fue de mucha ayuda tu tutorial felicitaciones!! y muchas gracias por tu aporte!! ahora una consulta cuando quiero agregar nuevos items a la lista me borra los que ya tenia cargados como puedo solucionar esto que me agrege los nuevos items al final dejandome todos cargados en mi lista, desde ya muchas gracias saludos!!

    1. Hola Pablo. Este tutorial está centrado en mostrar elementos. Lo que tienes que hacer es moficar el adaptador para que en el ArrayList añada datos y refresque el listado.

        1. Hola Ramon!! me podras ayudar no logro que me funcione, vi algunos otros tutoriales y logro que pagine mi carga pero me borra lo que ya tengo cargado en mi lista!!! en el adapter aplican 

          this.notifyDataSetChanged();

          pero no me doy cuenta como usarlo en el codigo que ya tengo!!

          1. ¿El this está aplicándose dentro del adapter? Si es en el Activity o Fragment no funciona

  23. Hola. Gracias por el blog. 

    He añadido un ratingBar, pero no soy capaz de recoger los votos. No se dónde debo poner el lister. Si podría ayudarme..

    Muchas gracias

    1. Simplemente utliza el método setOnRatingBarChangeListener() y instanciale un “RatingBar.OnRatingBarChangeListener” (más información en http://developer.android.com/reference/android/widget/RatingBar.OnRatingBarChangeListener.html). Un ejemplo puede ser:

      miRatingBar.setOnRatingBarChangeListener(new onRatingChanged(RatingBar elRatingBar,float votos, boolean siCambiadoDirectamentePorUsuario){

      //Hacer algo al cambiar los votos

      });

      1. Muchas gracias por la contestación. El tema es que no me aclaro muy bien. Tengo exactamente el Adepater como lo has publicado tu.
        En mi entrada.xml tengo dos textview y Rating Bar. Los dos textView los instancio en el método onEntrada cada vez que les paso una entrada nueva. 
        No se bien, dónde tengo que instaciar el Rating Bar, para luego hacer el método setOnRatingBarChangeListener

        Es decir: dónde isntancio el miRatingbar que me has dicho?

        Muchas gracias de antemano. No se si me estoy explicando 
        Exactamente lo que hagoe s mostrar dos text view y por cada uno quiero guardar lapuntuacion en un arraylist de enteros. Solo eso. 

         

        Gracias, si me puedes echar una mano te lo agradecería porque entrego en nada el proyecto. 

        1. Entiendo que tienes un RatingBar para cada elemento del listado, sobre como instanciar y controlar cada view tienes ejemplos en http://jarroba.com/expansion-listview/

  24. hola muchas gracias por este aporte ramon , me ha servido demasiado ya que apenas voy empezando con esto de la programacion en android me gustaria si me pudieras explicar como le puedo hacer para que la informacion introducida en vez de verla en un toast la pueda ver en un nuevo activity, te lo agradeceria mucho, gracias 

  25. Hola Ramon

    soy yo otra vez, hice lo siguiente en el OnItemClick, view.setBackgroundColor(color.anaranjado); y cuando pulso el primer Item cambia de color no solo el primer Item sino también el cuarto, y cuando es el segundo cambia de color tambien el quinto…..que estoy haciendo mal?

  26. perdon no fuí bien claro..pregunto si es posible cambiar el color del texto en el item cuando se haga clich en él…gracias

    1. Hola Milton.

      Sí, simplemente en el evento onItemClick() tienes que usar View que contiene las vistas del elemento pulsado. Entonces solo tienes que hacer un cambio de color de una View (por ejemplo con setBackgroundColor() cambias el fondo de la View).

  27. Hola Ramon….tengo una pregunta, como se hace para cambiar el color a un item de este listview cuando se haga click en él. Te agradecería la ayuda

  28. Hola, Ramón.

    En primer lugar me gustaría felicitarte por el blog. Estoy empezando con Android y me está sirviendo de gran ayuda.

    Mi problema es: me gustaría tener una lista con 4 elementos, pero cada uno con un layout diferente. ¿Podría hacerse con el adaptador que utilizas en este tutorial?, si es así, ¿cómo podría hacerse?

    Muchas gracias.

    1. Hola Fran,

      Se puede hacer tantos listados como necesites en tantos layouts como sean necesarios. Te recomiendo que hagas cada listado en un Fragments (tienes toda la infromación en http://jarroba.com/programar-fragments-fragmentos-en-android/). Luego cuando los tengas funcionando por separado, ya es tan fácil como poner los Fragments ubicados donde los necesites dentro de la misma Activity 😉

  29. Hola

    Ojala, me puedas ayudar

    Se detiene la ejecución en el emulador,

    Esto es lo que arroja el logcat:

    03-21 19:42:59.911 1926-1926/com.example.mauro.listado I/art﹕ Not late-enabling -Xcheck:jni (already on)
    03-21 19:43:03.176 1926-1944/com.example.mauro.listado D/OpenGLRenderer﹕ Render dirty regions requested: true
    03-21 19:43:03.179 1926-1926/com.example.mauro.listado D/﹕ HostConnection::get() New Host Connection established 0xae0d0e30, tid 1926
    03-21 19:43:03.200 1926-1926/com.example.mauro.listado D/Atlas﹕ Validating map…
    03-21 19:43:03.457 1926-1944/com.example.mauro.listado D/﹕ HostConnection::get() New Host Connection established 0xae0d0f90, tid 1944
    03-21 19:43:03.474 1926-1944/com.example.mauro.listado I/OpenGLRenderer﹕ Initialized EGL, version 1.4
    03-21 19:43:03.492 1926-1944/com.example.mauro.listado D/OpenGLRenderer﹕ Enabling debug mode 0
    03-21 19:43:03.535 1926-1944/com.example.mauro.listado W/EGL_emulation﹕ eglSurfaceAttrib not implemented
    03-21 19:43:03.535 1926-1944/com.example.mauro.listado W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xa6c21760, error=EGL_SUCCESS
    03-21 19:43:03.979 1926-1938/com.example.mauro.listado I/art﹕ Background partial concurrent mark sweep GC freed 28(1072B) AllocSpace objects, 0(0B) LOS objects, 11% free, 29MB/33MB, paused 1.215ms total 135.436ms
    03-21 19:43:04.156 1926-1938/com.example.mauro.listado I/art﹕ Background sticky concurrent mark sweep GC freed 35(2016B) AllocSpace objects, 1(36KB) LOS objects, 0% free, 44MB/44MB, paused 11.822ms total 28.561ms
    03-21 19:43:04.319 1926-1926/com.example.mauro.listado I/art﹕ Alloc sticky concurrent mark sweep GC freed 31(1456B) AllocSpace objects, 1(36KB) LOS objects, 3% free, 56MB/58MB, paused 1.123ms total 6.338ms
    03-21 19:43:04.327 1926-1926/com.example.mauro.listado I/art﹕ Alloc partial concurrent mark sweep GC freed 7(288B) AllocSpace objects, 0(0B) LOS objects, 6% free, 56MB/60MB, paused 1.148ms total 7.045ms
    03-21 19:43:04.336 1926-1926/com.example.mauro.listado I/art﹕ Alloc concurrent mark sweep GC freed 3(12KB) AllocSpace objects, 0(0B) LOS objects, 6% free, 56MB/60MB, paused 1.485ms total 8.575ms
    03-21 19:43:04.336 1926-1926/com.example.mauro.listado I/art﹕ Forcing collection of SoftReferences for 16MB allocation
    03-21 19:43:04.383 1926-1926/com.example.mauro.listado I/art﹕ Alloc concurrent mark sweep GC freed 0(0B) AllocSpace objects, 0(0B) LOS objects, 6% free, 56MB/60MB, paused 6.237ms total 46.106ms
    03-21 19:43:04.385 1926-1926/com.example.mauro.listado E/art﹕ Throwing OutOfMemoryError “Failed to allocate a 17280012 byte allocation with 4194304 free bytes and 7MB until OOM”
    03-21 19:43:04.385 1926-1926/com.example.mauro.listado D/skia﹕ — allocation failed for scaled bitmap
    03-21 19:43:04.386 1926-1926/com.example.mauro.listado D/AndroidRuntime﹕ Shutting down VM
    ——— beginning of crash
    03-21 19:43:04.390 1926-1926/com.example.mauro.listado E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.example.mauro.listado, PID: 1926
    java.lang.OutOfMemoryError: Failed to allocate a 17280012 byte allocation with 4194304 free bytes and 7MB until OOM
    at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:973)
    at android.content.res.Resources.loadDrawableForCookie(Resources.java:2423)
    at android.content.res.Resources.loadDrawable(Resources.java:2330)
    at android.content.res.Resources.getDrawable(Resources.java:758)
    at android.content.Context.getDrawable(Context.java:402)
    at android.widget.ImageView.resolveUri(ImageView.java:741)
    at android.widget.ImageView.setImageResource(ImageView.java:397)
    at com.example.mauro.listado.MainActivity$1.onEntrada(MainActivity.java:57)
    at com.example.mauro.listado.Lista_adaptador.getView(Lista_adaptador.java:33)
    at android.widget.AbsListView.obtainView(AbsListView.java:2344)
    at android.widget.ListView.makeAndAddView(ListView.java:1864)
    at android.widget.ListView.fillDown(ListView.java:698)
    at android.widget.ListView.fillFromTop(ListView.java:759)
    at android.widget.ListView.layoutChildren(ListView.java:1673)
    at android.widget.AbsListView.onLayout(AbsListView.java:2148)
    at android.view.View.layout(View.java:15596)
    at android.view.ViewGroup.layout(ViewGroup.java:4966)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:573)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:508)
    at android.view.View.layout(View.java:15596)
    at android.view.ViewGroup.layout(ViewGroup.java:4966)
    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
    at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
    at android.view.View.layout(View.java:15596)
    at android.view.ViewGroup.layout(ViewGroup.java:4966)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:573)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:508)
    at android.view.View.layout(View.java:15596)
    at android.view.ViewGroup.layout(ViewGroup.java:4966)
    at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2072)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1829)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1054)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5779)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
    at android.view.Choreographer.doCallbacks(Choreographer.java:580)
    at android.view.Choreographer.doFrame(Choreographer.java:550)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5221)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
    03-21 19:43:14.463 1926-1926/com.example.mauro.listado I/Process﹕ Sending signal. PID: 1926 SIG: 9

    1. Estás poniendo imágenes demasiado grandes. Reducelas o aplícales alguna copresión. Así mismo, cachéalas para evitar desbordamientos de memoria por las imágenes.

  30. Saludos amigos, segui su tutorial a la perfeccion y todo salio excelente! Solo modifique un aspecto y es que al seleccionar una entrada, en vez de desplegar un Toast para visualizar su informacion, lo hago en una nueva Activity, y es ahi donde viene mi duda. Como hago para pasar la imagen de la entrada a travez del intent? Sería de mucha ayuda una pronta contestación! Muchas gracias!

  31. Hola Ramon. Queria hacerte una consulta sobre los idiomas en android.
    Lo que yo quiero hacer es poder cambiar el idioma mediante un menu implementado en mi aplicacion. OJO no solo cambiar Ingles – Espaniol. Si no idiomas nativos como ser Aymara, Quechua. Gracias de ante mano

  32. Un ejemplo de como porder llenar un Listview personalizado desde un web service usando asp.net seria muy bueno seria algo asi:

    IMAGEN PRODUCTO
    IMAGEN precio codigo
    por favor ojala me puedan ayudar mi correo es [correo oculto por privacidad]

      1. Hola la verdad soy nuevo en android y ya pude conectarme a mi base de datos en sql server haciendo uso de web service, pero donde tengo muchos problemas es cuando quiero crear un ListView Personalizado por ejemplo

        IMAGEN *——–NOMBREPRODUCTO ———–*
        IMAGEN PRECIO PRODUCTO CODIGO PROD

        claro necesito leer datos desde mi servidor pero no encuentro un solo ejemplo parecido por favor ayúdenme lo hago por aprender

          1. Hola Ramon si el web service es usando Ksoap2 pero tengo problemas cuando intento usar el GetView ya que ahora mi ListView es personalizado cuando intento llamarlo desde el AsyncTask ojla puedas ayudarme ingrese a los links de las paginas que me enviaste y no se adecua mucho a lo que necesito ya que es un Listview Personalizado y este se llena por web service haciendo uso de otro hilo. gracias de ante mano Saludos desde Perú

          2. Son dos cosas separadas. Una vez que tengas obtenidos los datos con Ksoap2, tan solo tienes que pintarlos en el ListView como en este ejemplo (con hilos lo único que tienes que refrescar el listado con notifydatasetchanged() desde el Adaptador).

          3. No te puedo recomendar pues no lo he utilizado. Veo que jtds es una biblioteca para trabajar con Microsoft SQL Server en Java. Te podría servir si tu base de datos estuviera en el móvil (esta clase de bibliotecas se suele utilizar en el lado del servidor; y aun así, en Java existe Hibernate o MyBatis), cosa que creo que no te atañe, pues me has comentado que te devuelven los datos en un SOAP, por lo que no te sirve la biblioteca jtds en el lado del móvil.

  33. Hola, primero agradezco por el tutorial que esta muy bueno, la verdad que recién estoy empezando a programar y probé el código que si me funciono pero tengo una duda, es que probé en poner un ImageButton en vez del ImageView y cuando selecciono un items de la lista no me muestra los valores que seleccione es como sino funcionaria al dar click en un item.
    Esta es la duda que tengo no se como solucionarlo, de todas maneras te agradezco por el tutorial y por favor me darías alguna ayuda

      1. Hola Ramón,
        Primero te agradezco por tomarte el tiempo de responderme y también agradecerte por la ayuda muchas gracias ya despeje las dudas que tenia y te agradezco por eso.
        GRACIAS

  34. Siempre habra que crear un lista personalizada por cada objeto que querramos mostrar ¿? Imaginate si tendriamos 40 clases o.O !!!

    1. Hola Ernesto,

      No hace falta crear una lista personalizada si no lo necesitas (Te cuento como en http://jarroba.com/listview-de-android-en-pocas-lineas/). De cualquier manera, para cada lista un objeto no es tanto, sobre todo sabiendo que van a ser Activities o Fragments que destruya o cree los objetos cuando se necesiten.

      Si te refieres a los objetos del ArrayList, como son objetos POJO no deberían de cargar mucho en memoria al ser solo un poco de texto. Si necesitas liberar memoria siempre puedes cachear y poner referencias débiles. O rizando el rizo, solo cargar en memoria los objetos que ve el usuario, realizando la consulta a la base de datos cada vez que se necesite y liberando los objetos cuando no se necesiten (esto es lo más deseable, aunque lo más complejo).

  35. Hola, muchas gracias por tu tutorial antes que nada pero tengo un problema cuando ejecuto la app en el simulador o en mi dispositivo se crashea la activity dice: “Desafortunadamente [Nombre de la actividad] se ha detenido” algún consejo?

    Realmente gracias por tu web muy útil, ya inicie a leer vuestro libro esta buenísimo.

    1. De nada José, me alegro que te guste, ha sido una gran dedicación 🙂
      Sobre el error que comentas, es el error genérico de Android. Cópiame la traza del error del Android Logcat (cuando se produce el error donde sale más cantidad de texto en rojo). También comprueba que estés declarando la Activity en el AndroidManifest.xml

      1. Hola, por mera casualidad solucione el problema que tenia, era que no estaba consultando que el parámetro entrada:Object de la función onEntrada sea diferente de null pero ahora tengo otro problema, y es que solo se ve en la aplicación el ultimo elemento del “ArrayList datos” los demás elementos se ven también pero sin el titulo ni la descripción ni las imágenes que crees que sea?

        Te dejo mi MainActivity para que lo mires (Si tienes tiempo obviamente) y me puedas dar una mano.

        package com.worfu.jose.customlistview2;

        import android.support.v7.app.ActionBarActivity;
        import android.os.Bundle;
        import android.view.Menu;
        import android.view.MenuItem;
        import android.view.View;
        import android.widget.AdapterView;
        import android.widget.ImageView;
        import android.widget.ListView;
        import android.widget.TextView;
        import android.widget.Toast;

        import java.util.ArrayList;

        public class MainActivity extends ActionBarActivity {

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

        final ArrayList datos = new ArrayList();
        datos.add(new MyListModel(R.drawable.im_aguila, “Aguila”, “Águila es el nombre dado a las mayores aves depredadoras. Las diversas especies y subespecies de águilas pueden encontrarse en casi cualquier parte del mundo excepto en la Antártida.”));
        datos.add(new MyListModel(R.drawable.im_colibri, “Colibri”, “Los colibríes, también conocidos como picaflores, pájaros mosca o ermitaños, son un clado de aves apodiformes endémicas de América que cuenta con más de 300 especies.”));
        datos.add(new MyListModel(R.drawable.im_buho, “Buho”, “Búho es el nombre común de aves de la familia Strigidae, del orden de las estrigiformes o aves rapaces nocturnas.”));

        ListView listView = (ListView) findViewById(R.id.listView_mainActivity);
        listView.setAdapter(new UniversalListAdapter(this, R.layout.list_item_layout, datos) {
        @Override
        public void onEntrada(Object entrada, View view) {
        if (entrada != null && view != null) {
        TextView title = (TextView) findViewById(R.id.itemTitle);
        if (title != null)
        title.setText(((MyListModel) entrada).getTitle());

        TextView subTitle = (TextView) findViewById(R.id.itemSubtitle);
        if (subTitle != null)
        subTitle.setText(((MyListModel) entrada).getSubtitle());

        ImageView image = (ImageView) findViewById(R.id.itemImage);
        if (image != null)
        image.setImageResource(((MyListModel) entrada).getImageId());
        }
        }
        });

        onItemsTouched(listView);
        }

        private void onItemsTouched(ListView list) {
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView parent, View view, int position, long id) {
        MyListModel touched = (MyListModel) parent.getItemAtPosition(position);
        CharSequence text = “Elegido: ” + touched.getSubtitle();
        Toast toast = Toast.makeText(MainActivity.this, text, Toast.LENGTH_LONG);
        toast.show();
        }
        });
        }

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

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
        return true;
        }

        return super.onOptionsItemSelected(item);
        }
        }

        1. Huele a problema de pintado. Comprueba que el ArrayList se está recorriendo correctamente dentro del Adapter

          1. Gracias por tu pronta respuesta, acabo de revisar y no veo nada raro además también te digo que yo copie y pegue el adaptador que tu pusiste en el tutorial y luego escribí yo el resto de la app.

            Que me recomiendas? pongo un bucle dentro de la función getView() del adapter? (aun soy noob en android lo se)

            y por alguna razón desconocida ocurre esto también me gustaría decirte que cuando toco un elemento de la lista si me devuelve la descripción.

          2. Evita poner bucles dentro del getView(), este se repite para cada fila cuando se muestra al usuario y será demasiada carga.
            Mira que estén bien los datos dentro del ArrayList que se pinta.

          3. Hola, despues de un poco de trabajo descubri cual era el problema y lo describire a continuacion por si a alguien mas le ocurre:

            DESCRIPCION DEL PROBLEMA: Se crashea la app cuando se abre el activity, las variables donde se almacena el titulo, la descripcion y la id de la imagen regresan un null, ¿por que “#$#&/(&/( ocurre esto?

            El problema que yo tenia era que no sabia que la funcion findViewById() regresa una View si esta esta en el layout que le pasemos a la funcion setContentView(), si no esta tendremos que inflar la/las layouts de las cuales necesitemos seleccionar elementos.

            Y la solucion que hize fue hacer lo dice que haga jarroba en el codigo: si miran el codigo que puse arriba veran por ejemplo lo siguiente dentro de la funcion onEntrada(Object entrada, View view)

            TextView title = (TextView) findViewById(R.id.id_del_titulo);

            .. y deberia estar asi:

            TextView title = (TextView) view.findViewById(R.id.id_del_titulo);

            Y eso es todo la funcion getView() del adaptador se encarga de inflar la layout del diseño de la lista por lo que solo deberemos hacer eso.

            Aqui dejo un link de que me ayudo mucho a solucionar este problema:
            http://stackoverflow.com/questions/19078461/android-null-pointer-exception-findviewbyid

            Gracias Ramon por tu ayuda, y por el libro “Android 100%” esta muy bueno.

            Hasta pronto.

          4. Me alegro que funcionara Jose, esto de la programación al dar un par de vueltas se soluciona solo 🙂

  36. Hola de nuevo!

    Amigos, vieras que estoy intentando agregar el nuevo Material Design a mis apps. El problema es que no encuentro la manera de adaptarlo a mi antiguo diseño, o sea, a mis antiguas aplicaciones. En estas aplicaciones yo les hice temas generados de Android Generator (la página). Sólo consigo agregar el nuevo Material Design si hago apps sólo para celulares que tengan Android 5.0+, no puedo con versiones anteriores.

    Les agradecería mucho si me logran dar una ayudida.

  37. Buenas,
    Seguro que ya está preguntado antes pero no lo encuentro: ¿cuál sería el código si la info de los animales se cogiese de una tabla en una BBDD de una web? Es decir, todo exactamente igual pero en vez de escribir la info sobre el búho en el propio código, cogerla de una tabla en una web cuyos campos serían por ejemplo animal, descriptivo de animal.

    Mil gracias y enhorabuena por el blog!
    Javi

      1. Perdona, no me he explicado bien. Ya tengo la base de datos y la tabla creadas en una web, lo que no sé es cómo hacer el recorrido con el cursor y embeber eso dentro del código que has creado… gracias!

        1. Lo tienes ya hecho. Solo tienes que recorrer el cursor (con un while por ejemplo), e ir insertando cada dato en el ArrayList del ejemplo 🙂

  38. Hola de nuevo!

    Amigos, tengo una dudilla. Intento hacer un gridview con base adapter personalizado. Quiero que la altura de las celdas de mi grid sea dinámica, y que no se monte una celda encima de otra. Así como el grid de la aplicación “Keep” de Google. De ante mano gracias por la ayuda.

    1. El GridView es solo para hacer cuadrículas con cada cuadrado el mismo tamaño. Si quieres hacer que cada cuadro tenga un tamaño diferente tienes dos maneras:
      1 – La manera antigua usando GridLayout y jugando con las filas y columnas: http://developer.android.com/reference/android/support/v7/widget/GridLayout.html
      2 – Para hacer justo como en “Keep”, a base de tarjetas con CardView: https://developer.android.com/training/material/lists-cards.html

  39. Hola, que tal.
    ¿donde o como coloco le codigo de “”lista.setOnItemClickListener(new OnItemClickListener()”” ?
    Estoy trabajando con hilo (AsyncTask) ya que mis datos son de una BD externa, que funciona bien, pero cuando coloco el ClickListener me lanza NULL y se cae.

    1. Hola, aviso que ya lo solucioné.

      y para todos los que tengan el error del Null PointerException (o algo asi),
      espero que esto les sea de ayuda….

      lista=(ListView) findViewById(R.id.TU_LISTVIEW_EN EL LAYOUT);

      lo primero es declarar eso y se va el error.
      (por lo menos ese era el mio, gracias por todos estos tutos y guías y apoyo, seguiré esta pagina hasta que android sea exterminado, jejeje).

  40. Hola, era por si podías ayudarme, me salta un error de NullPointerException
    en la linea de
    texto_superior_entrada.setText(((Lista_entrada) entrada).getTexto());
    le he cambiado el nombre del metodo porque yo no quiero poner texto inferior y le he puesto solo uno

    luego al instante me salta error en la linea de
    onEntrada (entradas.get(posicion), view);

    gracias por todo tu aporte!

  41. Buenos noches Ramon, excelente aporte antes que nada. Tengo una consulta al momento de correr la aplicacion desde un dispositivo, aparece que un toast “Listado se ha detenido”, intente bugearlo y me di cuenta que antes de ingresar al lista.setAdapter(new Lista_adaptador(this, R.layout.entrada, datos), se va al lista.setOnItemClickListener, y como no tiene nada en la lista se detiene.Si no es mucha molestia me podrias decir cual es el problema, desde ya muchas gracias.

    1. Hola Adrián, molestia ninguna 😉

      Si se te está metiendo por el setOnItemClickListener() comprueba que no lo estés llamando desde otro lado, pues solo se debería de llamar cuando detecte la pulsación del usuario sobre el elemento de la lista.

  42. Hola! soy muy nuevo en Android, y con este tutorial pude hacer mi ListView muy facil! pero no logro darle estilo. Quiero que tenga una linea divisoria, un color… Pero no logro resolverlo. Vi en algunos tutoriales muestran listView con un formato muy similar al que quiero, y utilizan Android.Resource.Layout.SimpleListItem2, pero no logro aplicarlo a mi listview! Saludos!

    1. Hola Facundo,
      si estás ponindo el ListView desde XML puedes darle estilo a la línea divisora con los atributos: android:divider=”#FFFFFF” y android:dividerHeight=”10dp”. Sin embargo, si lo haces extendiendo de ListView (con getListView()), puedes obetener el ListView y añadirle los atributos con los métodos: setDivider() y setDividerHeight().

  43. HOLA!!! llevo dos semanas tratando de arreglar este error y nada!!! ya me voy a volver loco… escribo a ver si me ayudan un poco..

    Error:(9) Error: This class should provide a default constructor (a public constructor with no arguments) (app.android.sysjm.tiendaonline.Contenedor) [Instantiatable]

    en la clase Lista_entrada()

      1. Hola Ramon, gracias por tomarte la molestia de escribirme…. te coloco parte del codigo:

        ———- EN ESTA CLASE ES DONDE ME SALE EL ERROR —–
        public class Contenedor {
        public Contenedor(int imageView, String textView_titulo, String textView_desc){
        super();

        ———-
        public abstract class adaptador extends BaseAdapter {

        private ArrayList entradas;
        private int R_layout_IdView;
        private Context contexto;

        public adaptador(Context contexto, int R_layout_IdView, ArrayList entradas) {
        super();
        this.contexto = contexto;
        ———————–
        public class listado extends Activity {
        private ListView lista;

        protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.listado);

        ArrayList datos = new ArrayList();
        ———

        1. El erro lo tienes justo en la primera, no llames al “super()” en el contructor. Recuerda que realizar una llamada al “super()” es llamar al constructor de la clase padre, como en tu clase “Contenedor” no extiendes de ninguna clase padre, no hay ningún constructor padre al que llamar.

  44. Hola Ramon.

    Primero que todo gracia por dedicar parte de tu tiempo a estos tutoriales..Han sido de gran ayuda.
    Mi pregunta es: Sera posible almacenar en un listview o grisview un DataSet de un servicio web.

    La informacion que aparece despues de que oprimo invocar es la que quiero almacenar.. Te agradezco de antemano tu ayuda.

    1. Hola Liedsy,

      Android no procesa SOAPs de manera directa (por problemas de rendimiento entre otros inconvenientes de usar SOAP). Si puedes utiliza servicios JSON. Si no tuvieras otra que utilizar SOAP, existe la librería externa KSoap para Android (descárgala y mira la documentación en https://code.google.com/p/ksoap2-android/).
      Luego ya podrías hacer lo que quieras con los datos, como mostrarlos en el listado, aunque te recomiendo que antes de mostrarlo en el ListView lo almacenes en base de datos.

      1. Cordial Saludo Ramon.

        Gracias por tu pronta respuesta y tu sujerencia.Pero creo que no me hice entender.
        Mi problema no esta en la consulta del servicio,Mi problema como tal esta es en plasmar el resultado ocea el DataSet en la base de datos SQLite o en el listViw.
        [Dato borrado por seguridad. Más información en http://jarroba.com/faq/ ]
        Hasta el momento solo muestro un mensaje en el que compruevo que si me he conectado al servicio.

        resSoap = (SoapObject) envelope.getResponse();
        String WS = resSoap.getProperty(1).toString();

        if(resSoap != null){

        Toast.makeText(getApplicationContext(), “INFORMACION ” + WS , Toast.LENGTH_LONG).show();

        }
        else {
        Toast.makeText(getApplicationContext(), “No Responde” , Toast.LENGTH_LONG).show();
        }

      2. Quiero mencionar que ya he creado la base de datos lg_Bodegas con su respectiba tabla Ingreso y los campos correspondientes a la informacion del servicio..

      3. Hola Ramor. Puedes porfavor borrar linck del servicio que te envie.Es que la publicacion me puede generar problemas.
        Gracias.

        1. Ningún problema, ya he quitado el link.

          No hay que poner nunca información privada, links o correos que puedan comprometer la seguridad en cualquier página web o foro público. Cuando quieras poner un ejemplo en la que esté involucrada información privada, antes cámbialo lo suficiente como para no comprometer la seguridad, o directamente crea un ejemplo nuevo para no poner el original.

          1. Muchas gracias.

            En cuanto a la consulta, te cuento que logre almacenar toda la informacion en una variable ya no como mensaje sino como informacion como tal.
            Lo que pasa es que el mensaje es algo similar a lo que aparece en este linck:
            [Dato borrado por seguridad. Más información en http://jarroba.com/faq/ ]
            Basabdonos en este ejemplo: Logre que me aparezca de aqui en adelante en una variable.

            {NewDataSet = anyType {Tabla = anyType {USUARIO_CODIGO = 401; USUARIO_NOME = tc3; USUARIO_NUMERO_PARTICIPANTES = 1; USUARIO_DESCRICAO = anyType {}; USUARIO_LATITUDE = 0; USUARIO_LONGITUDE = 0; USUARIO_FOTO_PERFIL = anyType {}; USUARIO_DATA_CADASTRO = 2012-04-02T13: 37: 19,89 a 03: 00; USUARIO_DATA_ATUALIZACAO = 2012-04-02T13: 37: 19,89 a 03: 00; USUARIO_ATIVO = A; };

            No se como mostrar dato por dato (Couna por Columna)… Aclaro que la solucion que dan en linck no me funciona..

          2. No es un Json, por lo que no podrás utilizar la función propia de Android. Si lo tienes en un String tendrás que crear una función que divida el String y vayas guardando cada dato en una variable (en un objeto Pojo, como en el ejemplo en Lista_entrada.java).
            Un ejemplo para dividir un String en Java es:

            String miTexto = "www.Jarroba.com";
            String[] partes = miTexto.split(".");
            String tiene_www = partes[0];
            String tiene_Jarroba = partes[1];
            String tiene_com = partes[2];

            Una vez que lo tengas ya es seguir el ejemplo 😉

  45. Buenas noches, felicitarte por tu post justo es algo muy parecido que quiero hacer, pero mi duda es, si las imágenes los tengo desde un lugar Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) +nombreFoto+ “.jpg”
    como se haria para poder crear un objeto teniendo un .jpg porque veo que lo hacen asi: datos.add(new Lista_entrada(R.drawable.im_colibri, “texto”)

    pero no es un tipo R.drawable porque no esta la imagen dentro del proyecto, asi que mi duda va como convertir esa imagen jpg en un entero: int idImagen. Para que el constructor: public Lista_entrada (int idImagen, String textoEncima, String textoDebajo) { } lo reciba. Les agradezco su respuesta.

    1. Hola Paul, gracias por las felicitaciones,

      para hace lo de las foto guardadas tienes que obtenerlas directamente de la tarjeta de memoria (en este caso te tienes que olvidar de los enteros, ya que son para llamar a las imágenes que están en la carpeta drawable del proyecto) y dibujarlas como bitmap:

      ImageView iv = (ImageView) findViewById(R.id.miImageView);
      mImg.setImageBitmap(miImagenCargadaDeMemoria);

      1. Excelente este ejemplo, super util, lo mejor que he visto en internet, quisiera saber como puedo cargar las imagenes que van en cada item del listview desde una bd externa donde estan en campos blob, por una cuestion de falta de servicios y recursos me es indispensable tener las fotos (muy pequeñas) dentro de la base de datos y cargarlas en el listview, pero he probado tratar de agregar a la ” lista de entrada” y a la “lista_adaptador”, probando con Blob, tambien con byte[] pero al final siempre me da algun error, si pudieran aunque fuera indicarme el camino sería de mucha ayuda.

    2. Hola buen dia

      Quiero realizar la misma tarea que el colega solo que no entiendo como podria hacerlo , si pusieras un ejemplo mas especifico estaria perfecto 🙂

    3. Puede ser mas especifico en esta respuesta Admin 🙂 

      ImageView iv = (ImageView) findViewById(R.id.miImageView);
      mImg.setImageBitmap(miImagenCargadaDeMemoria);

  46. Hola! Muy practico tu ejemplo.

    Yo tengo una duda parecida a la de Rodrigo. Si yo quiero hacer una app para mostrar las noticias, es posible obtener esa informacion de una pagina especifica? Es decir, de una pagina web especifica obtener los articulos que se van subiendo y que vallan apareciendo en la app cuando se conecte a internet.

    Espero tu respuesta, gracias.

    1. Hola Cecilia,

      si tiene un servicio público sí (o de pago si quieres pagar por la información). Luego está el parseo de web, que no considero moral al tener derechos de autor los contenidos parseados, por lo que no lo recomiendo.

  47. Excelente, lo mejor en listados dinámicos que he visto. Pero te hago una consulta:
    Usas un on
    lista.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(..)}

    para que al hacer click en cualquier ubicación de la listView cree el toast; se puede hacer que el onClickListener sea efectivo sobre una parte de la lista, por ejemplo:
    Que al clicar la imagen suceda una cosa, pero al clickear en el titulo suceda otra??

    Desde ya muchas gracias

  48. HOLA…ESTOY APENAS APRENDIENDO A PROGRAMAR, UTILICÉ SU CODIGO Y FUNCIONA MUY BIEN PERO QUISIERA SABER COMO GUARDARLOS EN SHARED PREFERENCE LOS DATOS QUE OBTENGO DE LOS EDITTEXT…..GRACIAS

      1. Hola Ramón, gracias por responder;ya he aprendido a guardar en shared preference, el problema para es que yo seguí el codigo anterior de tu proyecto le añadí tres edittext para recoger los datos pero no se como guardar en shared los tres string que recoge y luego otro tres y así para ir llenando el listview ly uego recuperalos…te agradezco tu ayuda.

  49. Hola que tal !!
    Pude implementar lo explicado pero me esta pasando algo raro.
    En el ejemplo la lista tiene 8 items, si cargo 6 items a la lista se muestran perfecto en el emulador, al agregar uno mas la aplicación aborta con el siguiente error.

    Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread 1221

    Alguna pista que se les ocurra ?
    Muchas Gracias.

  50. Hola
    Como puedo hacer que se abra una nueva actividad al pulsar sobre un item de listview. Y que dicha actividad sea dianamica, es decir no crear una actividad para cada item, sino tener una plantilla que cambie la info de acuerdo al item del textview seleccionado

    Gracias

  51. fue el mejor ejemplo de listview que encontré muchas gracias!!! , cómo podría hacer lo mismo pero con una imágenes en la web???
    traté con lo siguiente:
    en esta parte tengo:

    datos.add(new Lista_entrada( id_k,HandlerImagen(“http://www.bigsomer.com/avr/mobile/images/139812.jpg”),”Usuario: “+ nickname_k+” “, fecha_k,
    observaciones_k,categoria_alumbrado,”Reportado”,estado_cero,
    “Asignado”, estado_cero, “Resuelto”, estado_cero,
    “Rechazado”, estado_cero));

    y en el método handler tengo:
    private Bitmap HandlerImagen(String img) {
    // TODO Auto-generated method stub
    String url1 = img; //AUNQUE SI COLOCO LA URL DE UNA IMAGEN FUNCIONA PERO SE REPITE SOLO ESA IMAGEN
    URL imagenUrl = null;
    Bitmap loadedImage;

    try{

    imagenUrl = new URL(url1);
    HttpURLConnection conn = (HttpURLConnection) imagenUrl.openConnection();
    conn.connect();
    loadedImage = BitmapFactory.decodeStream(conn.getInputStream());

    } catch(Exception ex){

    Log.e(“error image”,”errorim” ,ex);
    loadedImage=null;
    }

    return loadedImage;
    }
    pero no funcionan la imagen me sale en null

  52. Hola chiscos…muy buen post, y el tema super chevere, yo tengo una pregunta de pronto creen que se pueda hacer una estrucctura como esta:
    > Frutas:
    ->Naranaja
    ->Banana
    > Tuberculos:
    ->Patatas
    ->Yucas

  53. Hola
    Hay alguna forma de estar actualizando el listado de manera remota, por un web service o no se por que medio se pueda realizar. La idea es realizar una seccion de noticias y que se este actualizando la lista de noticias conforme pase el día.
    Saludos

  54. Excelente tutorial, esta bien claro y me ha saervido bastante para comprender la clase adaptador.

    Solo una consulta, en la clase Lista_Adaptador que indica el signo “?” al declarar el ArrayList, porque no usar ArrayList entrada; en ves de ArrayList entrada;

    Saludos!

    1. Hola Walter,
      utilizo el genérico símbolo de interrogación “?” en el Adaptador para que fuera compatible con cualquier nombre de clase que se ponga, no solo con “Entrada.java”. Se puede poner si te gusta más, funcionará igual 🙂

  55. Hola, tengo un problema, mi disp virtual no muestra el contenido de la app, de ninguna de las que he hecho, ni la tuya que descargué….
    agradecería ayuda

    1. Hola Bakir,
      Me das pocos datos, tengo que hacerte el test: ¿Estás lanzando el emulador con el círculo verde con una flecha? ¿Está bien configurado el proyecto con un emulador? ¿El proyecto tienen configurado en el AndroidManifest.xml una versión superior o igual al del emulador donde lo estás intentando ejecutar?

  56. Hola a todos!! mi problema es el siguiente: tengo una gridView que obtiene los datos de un WebService, en concreto obtine mesas de un restaurante, cada recuadro del gridview es una mesa. Mi problema es que cuando hago scroll las mesas no se representan correctamente, ya que se reutiliza el espacio y me enseña las mesas que quiere. Me gustaria saber si alguien le a pasado algo similar y si a podido resolverlo.

    Muchas gracias de antemano!!

  57. Hola tengo que conectar un web service asmx con android y no se como llenar una grid view e buscado y nada tal vez una pista (ah recibo una lista en xml y no se como pasarla a la grilla). Saludos

    1. Hola jimmy,

      no he tenido oportunidad de trabajar con Asmx, con lo que no sé en qué formato te devuelve el servicio. Si es JSON es muy sencillo, si es con SOAP es un poco más largo y menos recomendable en Android pero también se puede hacer. me dices.

  58. Hola Ramón:

    Basándonos en tu ejemplo, como haría para detectar si se a tocado (click) ,[imagen_entrada] o [texto_superior_entrada], ya que en función de ello debería hacer diferentes acciones.

    Muy bueno el tutorial y gracias anticipadas

    AP

  59. Hola buenas tardes…

    estoy totalmente atascado con algo que creo muy simple (entre comillas). No es otra cosa que llenar un listview. Me explico:
    – 1º consulto base de datos (SQLite) y obtengo el resultado en una variable Cursor. (todo campos de texto)
    – 2º creo una clase que representara al modelo de datos a mostrar en el listview, en concreto tres campos: foto (texto con la ruta para luego mostrar en un ImageVIew del ListVIew), nombre y descripcion.
    – 3º Creo el adaptador al que le paso un arraylist con los datos de la clase modelo, previametne transformé el cursor en ese arraylist (básicamente por dos motivos: 1. no fui capaz de cargar el listview directametne desde el cursor y, 2.uno de los campos debo transformarlo en una imagen (bitmap) para visualizarlo en el imageview del listview)
    – 4º enlazo el adapter con el listview y… outofmemory ¡¡¡ y solo tengo tres registro de prueba!!!
    Brujuleando encontré que hay que escalar la foto original para adaptarla al imageview y que no chupe tanta memoria, así que lo hiceint ancho = bitmap.getWidth();
    int alto = bitmap.getHeight();

    float escaloancho = ((float) 100) / ancho; //100dp es el tamaño del imageview
    float escaloalto = ((float) 100) / alto;

    Matrix matrix = new Matrix();
    matrix.postScale(escaloancho, escaloalto);

    Bitmap esBitmap = Bitmap.createBitmap(bitmap, 0, 0, ancho, alto,
    matrix, true)

    ¡¡Bingo funciona!! me carga los tres registros sin problema (habría que ver qué hace con muchos más)… salvo que tarda unos 10-15 segundos en mostrar el listview generado… ¡¡¡muy lento para tres registro!!! ¿¡¡y cuando tenga 200-300— qué sé yo?!!!

    Alguna sugerencia???… mencionar que convierto la ruta a la foto tipo string en bitmap directametne en el adapter al rellenar los views del listview y lo asigno al imageview con SETIMAGEBITMAP.

    También en el adaptador, antes de asignar la foto al imageview del listview la escalo.

    A parte de mi ineptitud (cuyo único consuelo lo encuentro en mi experiencia de unos meses en android), cuál puede ser el problema de que tarde tanto en cargar el listview????

    Por cierto, el listview lo muestro en un fragment donde también tengo un mapa de google y los dos aparecen en pantalla al mismo tiempo transcurridos esos 10-15 segundos.

    ¡¡¡Ayudaaaa!!

    Gracias por anticipado…

    P.D.: aunque me he matriculado en un curso a distancia, aprendo más con vuestro blog que con el curso. Gracias también por vuestros aportes.

    1. hola otra vez…

      he metido 6 registros y han aumentado los tiempos de espera, pero ahora veo también que la hacer scrool el el listview va ¡¡¡lentísimo!!, hasta parece que se queda y luego salta de golpe a la posición en que debería estar.

    2. Hola Nitram,

      hay que animarse, que una vez lo hagas ya verás que fácil es 😀

      El problema de los ListView de Android es con las imágenes, como bien dices, se desborda la memoria en un error OutOfMemory. La solución de hacerlas pequeñas es la óptima. Además, para optimizar más es necesario recurrir al cacheado de imágenes en el listado (puedes encontrar un ejemplo de como se hace en http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html).

      De cualquier manera -y aunque sea más laborioso, para que quede todo perfecto- lo suyo es que en una primera carga del Fragment del listado descargues algunas imágenes (el resto habría que paginarlas desde el servidor) y estas se reduzcan (o vengan reducidas, que sería lo suyo, para ahorrar ancho de banda), luego almacenarlas en memoria del móvil. Así al volver al listado por segunda vez no hay que realizar la descarga completa de todas las imágenes, solo las que faltan (hemos ahorrado datos, consecuentemente batería, y aumentado la velocidad de procesado y de respuesta al usuario). Sé que esto es un trabajo más laborioso, pero cuando tratamos ya con imágenes, vídeos o ficheros de gran tamaño, hay que pensar si compensa descargarlo todo cada vez o una única vez.

      Espero haberte aclarado algo.

      1. Ok… nuevamente muchas gracias.

        Decir solo q el viewholder ya lo tengo implementado y q las imagenes las cojo de la tarjeta sd, almacenadas ahi desde la camara.

        No se si el problema estara en q escalo las imagenes todas cdo paso del cursor al arraylist.

        Lo seguire intentando a ver q consigo.

        Otra vez… muchas gracias

    1. Hola Alejandro,
      no podemos dar soporte de webs ajenas, de esto se tiene que encargar quien lleve ese blog. De cualquier manera, le he echado un ojo y utiliza su propia librería, no es oficial de Android y no te puedo ayudar pues la desconozco 🙁

      Para un ListView horizontal te puedo recomendar algo más fácil: que hagas un GridView de una sola fila, que es lo mismo, con nuestro tutorial te va a funcionar seguro 😀

  60. Hola Ramon, el gusto de saludarte. Paso a contarte mas o menos mi situacion. Estoy desarrollando una aplicacion para un final en la universidad, en la cual pueda crear una lista para el super-mercado, y en la misma poder cargar diversos productos con sus respectivos precios. Luego, al hacer una consulta, tendria que traerme un ListView con cada item que representa una lista, y al hacer click, me muestre un detalle de los productos cargados y el precio total de la compra. Se entiende? Muchas gracias de antemano.

      1. Muchas gracias por responder y permiteme felicitarte por cada post, tu trabajo y el de tu compañero es realmente muy bueno y se nota la dedicacion y entusiasmo que le dedican a cada uno de ellos. Voy a tratar de seguir de pies a cabeza la ayuda que me indicas. Cualquier problema estare en contacto. Saludos desde Argentina

  61. Hola, estoy empezando con esto de android, y agradecería muchisimo un pequeño ejemplo de la funcion onEntrada, estoy un poco perdido con el concepto Handler, muchisimas gracias de antemano.

      1. Lo primero gracias por contestar, y tan rápido, estoy hecho un lío, lo que mas me confunde es lo que leo comentado justo encima de la funcion onEntrada:

        “…Devuelve cada una de las entradas con cada una de las vistas a la que debe de ser asociada …”

        Lo que hay que hacer es recoger la información que contiene el Objeto y guardaros en los TextView o lo que sea que contenga la vista???

        Muchas gracias de nuevo, y perdón por las molestias.

        1. Disculpa, ya me ha quedado claro, he intentando, pero veo que no se puede, borrar mi respuesta.

          Felicidades por el currazo que os pegais.

  62. Hola Ramón,

    Necesito ayuda para realizar una especie de carrito de compra que agregue y elimine los productos, al final calcule el total, resultado total de los diferentes descuentos de cada producto, es algo sencillo, tipo lista de compra de producto, no necesito base de datos, quiero algo mas sencillo, agradezco tu pronta respuesta.

  63. Hola Ramón,

    Tengo muchas dudas, pero empezaré por la que creo no me deja ver las cosas claras: en ese ejemplo extiendes una Activity mientras que en el ejemplo de “en pocas líneas” extiendes una ListActivity.
    ¿Cuál es el motivo real?
    Saludos y gracias por responder.

    1. Hola,

      Son dos maneras diferentes de hacer un ListView, ambas totalmente válidas. Cada uno tiene sus ventajas:
      -Si lo haces desde un Layout XML (), puedes acoplarlo como si fuera una imagen u otra cosa directamente desde los tags XML
      -Si lo haces desde Java, heredando de ListActivity, te ahorras algo de código como el Layout XML, pues ya te lo da Android hecho.
      -Si lo haces desde Java, heredando de ListFragment (el que principalmente recomiendo hoy día, aunque para éste tienes que entender Fragments http://jarroba.com/programar-fragments-fragmentos-en-android/), es muy útil por su modularidad a la hora de colocarlo en diferentes diseños
      Espero haberte aclarado las dudas 🙂

      1. Hola Ramón,
        pues la verdad es que ahora estoy peor. Obtuso que estoy hoy.Me explico:
        – pero si en los dos casos utilizas un LayoutXML??
        – porqué con ListActivity me ahorro código?

        Gracias adelantadas a la contestación.
        Saludos

        1. En ambos casos uso un Layout XML para diseñar la entrada individual, pero en el que heredo no utilizo uno para el ListView (de ahí que te ahorres código), echa un vistazo en ambos ejemplos y verás que es sencillo 🙂

  64. Hola, genial la explicación, muchisimas gracias!
    Tengo una duda, cuando implemento una listview o una expandablelistview, y le asigno un clicklistener a cada item, una vez que hago click en un item, al intentar hacer click nuevamente sobre ese item no responde, es como que guarda el ultimo item clickeado y recien al clickear otro vuelve a responder, no se si soy claro.
    Hay alguna forma de permitir que se pueda clickear varias veces un mismo item y que responda el oyente?
    Gracias!
    saludos

  65. Oye disculpa, como puedo importar las imagenes y colocarlas en el imageview?? para que me aparezcan en mi codigo sin errores.

  66. Hola, de verdad sus tutoriales son lo maximo me an ayudado muchisimo, e implementado su adapter en muuuchisimos casos y me a funcionado en toodo lo que e echo… pero horita estoy en un problema, tengo un listview en otro listview y extraigo todos los datos por sqlite, en uno de los listview tengo radiogroup con radiobuttons creados dinamicamente, el detalle es que cuando llego al final del listview cuando vuelvo a subir todas las modificaciones que hize anteriormente no se realizan, por lo q es necesario actualizar mi listview para ver mis modificaciones… se que tngo q usar notifydatasetchanged() pero no me agarra y en realidad no se donde ubicarlo en el adatador o en la clase principal…. ayuda porfavor

    1. Es muy sencillo, ya verás 🙂

      como bien dices, tan solo tienes que usar el método notifyDataSetChanged() de alguna clase que herede de BaseAdapter (es decir, del Adaptador que uses para el listado). Puedes utilizar el Adaptador del listado con getAdapter(). Te devolverá el Adaptador y podrás llamar al método notifyDataSetChanged(). Ten en cuenta que notifyDataSetChanged() trabaja sobre el hilo principal, pues modifica las vistas (quiero decir, que si lo usas desde un hilo en segundo plano, dará error).

      También puede servirte el siguiente tutorial para los radiogroups sobre listas: http://jarroba.com/expansion-listview/

  67. Hola Ramón un tutoriales estupendo. Estoy empezando a programar en android y tengo una duda sobre los listview. mi pregunta es por ejemplo si creo un listview con tres items quisiera saber si cada una de ellas podrían realizar diferentes acciones al pulsar cada item ya que cada una no tendrían nada en común.Gracias

      1. Hola Ramon gracias por el aporte, en realidad no se trata solo de tres item sino más, es mas o menos como lo tienes hecho en el ejemplo pero en mi caso quisiera describir todos los negocios de mi localidad dando una descripción del mismo y a su sitiación geográfica, pero cada negocio lo querria identificar con su categoria correspondiente, es decir en primer lugar hacer un listview donde aparezcan las diferentes categorias y una vez pulsada cada categoria acceder al listview correspondiente dando su descripcion. Cual sería la mejor forma de realizarlo?
        Gracias.

        1. Tienes varias opciones para sublistados. Teniendo un listado inicial, al pulsar un elemento abre otra Activity (o carga un Fragment adyacente) con el otro listado. Otra opción es utilizar Spinner para elegir las localidades. O también crear un sublistado dentro de la lista, aunque esto ya requiere modificar el adaptador. Depende de lo que necesites 😉

    1. Para cambiarlo te recomiendo que directamente cambies el color del texto en entrada.xml, ahí lo puedes hacer directamente con el entorno gráfico. Si lo quieres hacer dinámico (aunque te lo recomiendo menos, pues realentiza), puedes modificarlo en el onEntrada(), por ejemplo:
      texto_superior_entrada.setTextColor(Color.RED);

  68. Hola de nuevo!

    Tengo la siguiente duda. He visto que para aprovechar el espacio cuando el celular está de forma horizontal, el app Play kiosco pone como 2 listview en la pantalla, uno a la par de otro. Saben si usan el mismo listview, pero lo divide en 2 columnas, o es que sí ponen 2 listview?? Si es un mismo listview, cómo se hace?? Gracias de antemano.

  69. Hola Ramón,
    en primer lugar enhorabuena por los tutoriales. Están muy bien explicados y el código funciona perfectamente. He estado probando el código y funciona sin problemas hasta que realizo la modificación de añadir un botón a la entrada, en ese momento la funcion “lista.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView pariente, View view, int posicion, long id)” deja de funcionar. Supongo que el adaptador tiene que cambiar para funcionar con botones. Me podrías indicar en que consiste ese cambio.

    Gracias

  70. La aplicacion me muestra estos problemas:

    05-07 23:27:02.733: E/AndroidRuntime(273): FATAL EXCEPTION: main
    05-07 23:27:02.733: E/AndroidRuntime(273): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.loseweight/com.loseweight.MainActivity}: java.lang.NullPointerException
    05-07 23:27:02.733: E/AndroidRuntime(273): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
    05-07 23:27:02.733: E/AndroidRuntime(273): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
    05-07 23:27:02.733: E/AndroidRuntime(273): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
    05-07 23:27:02.733: E/AndroidRuntime(273): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
    05-07 23:27:02.733: E/AndroidRuntime(273): at android.os.Handler.dispatchMessage(Handler.java:99)
    05-07 23:27:02.733: E/AndroidRuntime(273): at android.os.Looper.loop(Looper.java:123)
    05-07 23:27:02.733: E/AndroidRuntime(273): at android.app.ActivityThread.main(ActivityThread.java:4627)
    05-07 23:27:02.733: E/AndroidRuntime(273): at java.lang.reflect.Method.invokeNative(Native Method)
    05-07 23:27:02.733: E/AndroidRuntime(273): at java.lang.reflect.Method.invoke(Method.java:521)
    05-07 23:27:02.733: E/AndroidRuntime(273): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    05-07 23:27:02.733: E/AndroidRuntime(273): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    05-07 23:27:02.733: E/AndroidRuntime(273): at dalvik.system.NativeStart.main(Native Method)
    05-07 23:27:02.733: E/AndroidRuntime(273): Caused by: java.lang.NullPointerException
    05-07 23:27:02.733: E/AndroidRuntime(273): at com.loseweight.MainActivity.onCreate(MainActivity.java:36)
    05-07 23:27:02.733: E/AndroidRuntime(273): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    05-07 23:27:02.733: E/AndroidRuntime(273): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
    05-07 23:27:02.733: E/AndroidRuntime(273): … 11 more

    1. Este error indica “java.lang.NullPointerException”. Revisa el código, pues en el MainActivity.java estás pasando un parámetro a null. Lo más probable es que una View se te haya olvidado buscarla con findById(), o que estés buscando una View que no está en el diseño (recurso Layout) que quieres usar en esa Activity.

      1. Gracias, lo que pasa es que yo cuando hice el nuevo proyecto , en el layout me aparece el mainActivity.xml pero siguiento tu tutorial solo veo que tu solo tienes el entrada y el listado, entonces le cambie el nombre para entenderlo bien, entonces como hago para remplazar ese (mainActivity por entrada como tu lo tienes en el tutorial).

        1. No es necesario, fíjate a que en el “MainActivity.Java” en el “setContentView()” no llamo a “activity_main.xml” sino a “listado.xml”. AL final tienes el proyecto entero para descargar, échale un vistazo a todo el conjunto.

      2. En en mainactivity.java yo lo tengo asi:

        lista = (ListView) findViewById(R.id.ListView_listado);
        lista.setAdapter(new Lista_adaptador(this, R.layout.entrada, datos){
        @Override
        public void onEntrada(Object entrada, View view) {
        if (entrada != null) {
        TextView texto_superior_entrada = (TextView) view.findViewById(R.id.textView_superior);
        if (texto_superior_entrada != null)
        texto_superior_entrada.setText(((Lista_entrada) entrada).get_textoEncima());

        TextView texto_inferior_entrada = (TextView) view.findViewById(R.id.textView_inferior);
        if (texto_inferior_entrada != null)
        texto_inferior_entrada.setText(((Lista_entrada) entrada).get_textoDebajo());

        ImageView imagen_entrada = (ImageView) view.findViewById(R.id.imageView_imagen);
        if (imagen_entrada != null)
        imagen_entrada.setImageResource(((Lista_entrada) entrada).get_idImagen());
        }
        }

        1. Está muy bien. Ahora solo tienes que asegurarte que estés llamando al diseño apropiado en el setContetnView(), que tenga las Views (las que buscas con findViewById() ) necesarias para que no lance una excepción de tipo null 🙂

      3. Hola en realidad no se que pasa, he revisado el codigo y lo compare con el tuyo y se encuentra todo bien, pero me sigue apareciendo ese error, no se que pueda ser si el codigo esta bien.

        1. Por los datos que me has enviado parece que no te está encontrando el listado, fíjate en la línea:
          ListView lista = (ListView) findViewById(R.id.ListView_listado);

          Y también fíjate en la línea del:
          setContentView()
          Esta última ha de tener asociado una diseño que exista y contenga al listado con id: ListView_listado. En otro caso te dará ese error.

          1. Hola mcuhas gracias ya solucione, ahora tengo una ultima pregunta es que quiero colocarle un menu donde tenga un opcion salir de la aplicacion, entonces lo he realizado pero no me funciona y me aparece este error:

            [2014-05-14 11:52:27 – LOSEWEIGHT] W/ResourceType( 3024): ResXMLTree_node header size 0 is too small.
            [2014-05-14 11:52:27 – LOSEWEIGHT] C:UsersEliana-DesktopLOSE WEIGHTLOSEWEIGHTresmenumain_.xml:3: error: Error: String types not allowed (at ‘icon’ with value ‘drawable/salir’).

            he colocado el string y en menu

            luego llame en el mainactivity.java asi

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

            public boolean onOptionSelected (MenuItem Item){
            switch(Item.getItemId()){
            case R.id.salir:
            finish();
            return true;
            default :
            return super . onOptionsItemSelected ( Item );
            }
            }
            }

          2. Parece que no está bien construido el XML del menú. Si te fijas nos está diciendo que en el atributo “icon” le está llegando un String que no está permitido, pues pide un id (concretamente el id de una imagen). Falta el “@” al texto. Tiene que quedar algo así:
            android:icon=”@drawable/salir”

  71. Hola Ramon no tengo ningun error en el codigo solo unas advertencias en el layout entrada [I18N] Hardcoded string “Descripción del contenido de la imagen”, should use @string resource.

    cuando yo quiero ver la aplicacion en el emulador me aparece asi “the application xxxx(process com.xxx) has stopped unexpectedly. please try again.

    Ayuda por favor para solucionar el problema.

    1. Te respondo a la advertencia por aquí y al error en el otro comentario.

      La advertencia que dice:
      [I18N] Hardcoded string “XXXXXX”, should use @string resource
      Sólo indica que es más apropiado poner los textos (String) en el fichero de String.xml.

  72. Ok Ramon muchas gracias, ya solucione este problema, pero tengo otro y es en el emulador, me aparece “the application (xx) has stopped unexpectedly. please try again.
    “forse close” , no se que hacer, ya en el codico no tengo errores, como puedo solucionar esto o sera que estoy haciendo algo mal.

    1. Ese error es genérico, para ayudarte necesito algo más concreto. En el momento en el que de el error en el emulador, aparecerá en el logcat un montón de líneas de color rojo indicando el error. Mira a ver si te da pistas las primeras líneas o cópiamelo 😉

  73. Hola! Muchas gracias por tan bien explicado tutorial! Bueno pues es mas dcirles que me funciono a la primera y haciendo el codigo por mi mismo(sin descargar el que postearon) y funciono de maravilla! Gracias!

    Aprovecho para molestarlo y preguntarles: Como podría yo pasar (o mas bien mostrar en otro activity) la informacion que seleccione en el ListView?

    Quisiera saber que es lo que debo “halarme” en el Intent?
    Entiendo que mi Intent debera ir en vez del Toast verdad=? pero no me queda claro, que debo tomar de aqui para mostrar en mi otro activity, y en el otro activiy como puedo tomarlos?
    lista.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView pariente, View view, int posicion, long id) {
    Lista_entrada elegido = (Lista_entrada) pariente.getItemAtPosition(posicion);

    CharSequence texto = “Seleccionado: ” + elegido.get_textoDebajo();
    Toast toast = Toast.makeText(MainActivity.this, texto, Toast.LENGTH_LONG);
    toast.show();
    }
    });
    muchas gracias por su ayuda, igual si no responden les estoy muy agradecido por el tuto!! (Y)

    1. Buenas Alejandro,

      Sí, el Toast lo tendrías que quitar y poner ahí lo que necesites, como lanzar una nueva Activity. Tenemos un ejemplo de como abrir otra Activity en: http://jarroba.com/activity-entender-y-usar-una-actividad/. Solo te queda pasarle los datos al Intent (como el id del elemento que se ha pulsado, o lo que necesites).

      Un ejemplo para guardar un valor en un Intent y además abrir la otra Activity sería (del ejemplo de http://jarroba.com/activity-entender-y-usar-una-actividad/):
      Intent intent = new Intent(this, Flexiones.class);
      intent.putExtra(“CLAVE DE ESTE EXTRA”, “Un valor que quiera pasar”);
      startActivity(intent);

      Y para recoger el valor en la otra Activity desde el Intent:
      Intent intent = getIntent();
      Bundle extras = intent.getExtras();
      String result = extras.getString(“CLAVE DE ESTE EXTRA”, “valor por defecto”);

      1. Hola Ramon muchas gracias!
        La verdad no se porque me complicaba tanto, quiza me aturdía la idea de estar trabajando con arreglos en un listview, pero bueno disculpen mi ignorancia.

        Al final te hice caso y lo hice asi, por si a alguien le ayuda:(al mostrar el listview y pulsar sobre cualquiera de los items se abriba otra actividad mostrando mas descriptivamente)

        lista.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView pariente, View view, int position,
        long id) {
        // TODO Auto-generated method stub
        Lista_entrada elegido = (Lista_entrada) pariente.getItemAtPosition(position);
        Intent i = new Intent(Noticias.this, Display.class); //A que actividad enviare los items
        i.putExtra(“imagen”, elegido.getIdImagen()); //halando imagen
        i.putExtra(“titulo”, elegido.getTextoEncima()); //halando titulo
        i.putExtra(“debajo”, elegido.getTextoDebajo()); //halando descripcion
        startActivity(i); // ir a la otra actividad

        }
        });

        #################################################################
        Display.class (Activity que recibe los parametros enviados desde el listview)

        public class Display extends Activity {

        private ImageView image;
        private TextView titulo, noticia;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.display);

        image = (ImageView)findViewById(R.id.imageView_imagen2);
        titulo = (TextView)findViewById(R.id.textView1);
        noticia = (TextView)findViewById(R.id.textView2);

        Bundle bundle = getIntent().getExtras();

        int idImagen = bundle.getInt(“imagen”);
        String urlImagen = String.valueOf(idImagen);

        String idTitulo = bundle.getString(“titulo”);
        String idDebajo = bundle.getString(“debajo”);

        image.setImageResource(idImagen);
        titulo.setText(idTitulo);
        noticia.setText(idDebajo);

        }

        }

  74. Hola ¿qué tal? Se que ya tiene algún tiempesito que has publicado este post, pero realmente me ha sido muy útil… estamos intentando desarrollar una aplicación y estamos utilizando el listview como componente principal para mostrar las diferentes categorias que se tienen contempladas… En fin… intentando implementar una nueva “mejora” nos hemos topado un problema que realmente no podemos resolver y hemos buscado en muchos lugares y realmente no hemos encontrado la forma de resolverlo… Veras… Hemos añadido el componente Spinner… y queremos que de acuerdo a la elección que el usuario realice en el Spinner, nuestro listView se actualice también…. Teníamos pensado comprar uno de los elementos que contiene el viewlist por ejemplo:
    datos.add(new Lista_entrada(R.drawable.im_buho, “BUHO”, “Nocturno”));
    datos.add(new Lista_entrada(R.drawable.im_aguila, “AGUILA”, “Diurno”));
    datos.add(new Lista_entrada(R.drawable.im_murci, “MUERCIELAGO”, “Nocturno”));

    Queremos que se muestren solamente todos los elementos del ListView que contienen la palabra “nocturno”… Pero no sabemos como manejar el arraylist para poder comprar y buscar esa palabra… ¿nos podrías ayudar? Te lo agradeceríamos infinitamente.

    1. Buenas Rebeca,
      Si lo tienes en una base de datos es sencillo (cosa que recomiendo), con hacer una consulta SELECT filtrada por el WHERE para que te devuelva los nombres que necesitas y pintarlos en el gráfico vale 🙂

      1. Buenos dias, quisiera hacer una aplicacion que contenga una lista personalizada, que contenga : Nutricion, ejercicio,tips y un cuestionario, quiero reflejarlo en una lista personalizada y que cuando uno seleccione entre a otra actividad que muestre informacion basica.

        Hasta el momento tengo el proyecto creado, tengo 1 layout que llama Activity_main.xml y el java que se llama MainActivity.java, ademas de haber colocado ya las imagenes en la carpeta Drawable.mdpi.

        Por favor, quiero empezar pero me confunde un poco.

          1. Hola Ramon, he seguido el tutorial pero me arroja un error , no se porque por fa podrias aclararme:

            El codigo en la lista_entrada es este, entonces me aparece error en la 3ra linea cuando se define la lista_adaptador.

            package com.loseweight1;

            public class Lista_adaptador {
            public abstract class Lista_adaptador extends BaseAdapter{
            private ArrayListentradas;
            private int R_Layout_IdView;
            private Context contexto;
            public Lista_adaptador (context contexto,int R_layout_IdView,ArrayListentradas){
            super();
            this.contexto=contexto;
            this.entradas=entradas;
            this.R_Layout_IdView=R_Layout_IdView;

            }
            public View getView(int posicion, View view, ViewGroup pariente) {
            if (view == null) {
            LayoutInflater vi = (LayoutInflater) contexto.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = vi.inflate(R_layout_IdView, null);
            }
            onEntrada (entradas.get(posicion), view);
            return view;
            }
            public int getCount() {
            return entradas.size();
            }
            public Object getItem(int posicion) {
            return entradas.get(posicion);
            }

            @Override
            public long getItemId(int posicion) {
            return posicion;
            }

            public abstract void onEntrada (Object entrada, View view);

            }
            }

          1. Hola, tengo otro error en el activiy_main , no se de donde sale.

            Multiple annotations found at this line:
            – The end-tag for element type “LinearLayout” must end with a ‘>’
            delimiter.

            esto en la linea de

            que puede ser?

          2. A algunos de los tags del XML del diseño (Layout) del activity_main.xml le falta algún símbolo >. Para el LinearLayout tiene que estar los tags del siguiente modo:
            <LinearLayout>
            </LinearLayout>
            Probablemente tengas algo así:
            <LinearLayout>
            </LinearLayout “Falta un >”

          3. Este error marca que has puesto una clase anidada con el mismo nombre que la clase envolvente y crea ambigüedad. Fíjate que has puesto:
            public class Lista_adaptador {

            public abstract class Lista_adaptador extends BaseAdapter{
            }

            }
            Cuando seguramente probablemente te sirviera con:
            public abstract class Lista_adaptador extends BaseAdapter{
            }

  75. Muchas gracias por todo esto, viene muy bien explicado!!

    A ver si alguien puede compartir el código de como adaptar esto para hacerlo con datos recogidos de un Json.

  76. Buenos días!

    Su aporte ha sido muy satisfactorio para mí y ahora necesito ayuda con algo tan simple, pero que me ha estado dando problemas. Desde hace como 4 días hice este tuto, pero le agregué CAB. Cuando hago como un LongClick sobre un listview item, se activa el CAB y me imprime lo que selecciono. El problema es que cuando selecciono items en modo CAB, no me resalta la línea, y por ende no se ve lo que está seleccionado en modo CAB. En resumen, sí lo selecciona, pero no lo resalta. Les agradecería la ayuda, gracias!

    1. Buenas Drey,

      para la Contextual Action Bar (CAB) el efecto de marcado a nivel de vista no se hace automáticamente, sino que tienes que cambiar el fondo de cada elemento de listado con setBackgroundColor(). Lo puedes realizar directamente sobre el método que sobrescribes de onItemCheckedStateChanged() del MultiChoiceModeListener 🙂

      1. Buenas noches!

        Pero si le pongo el setBackgroundColor(), lo que va a hacer es cambiarme el color de todo el ListView. Lo que yo quiero hacer es cambiar el color del item del ListView seleccionado, cuando activo el CAB. Te agradecería la ayuda.

        1. Lo siento, no había leído bien.

          De todos modos, he usado el lista.getChildAt(position).setBackgroundColor(Color.BLUE); pero no es exacta, porque depende de la posición que escoja y la cantidad que tenga, se cae el app. He buscado y lo que necesito es como obtener la fila de la lista y cambiarle el color al mismo tiempo. También he intentado con setOnItemSelectedListener(), haciendo view.setBackgroundColor(); pero éste me da problemas a la hora de cambiarle el color cuando quito la selección. Tons, no sé qué hacer! Agradecería su ayuda!

          1. El código para marcar y desmarcar, para que cambie el fondo, podría ser este:
            @Override
            public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
            View elemento = getListView().getChildAt(position);
            if (checked) {
            elemento.setBackgroundColor(Color.CYAN);
            } else {
            elemento.setBackgroundColor(Color.TRANSPARENT);
            }
            }

          1. Buenas noches!

            Como ya había mencionado, el getChild() no es estable. Por qué? getChild() trae los views que se ven en la pantalla, o sea, si caben 6 items en la pantalla, éso es lo que te va a permitir cambiar color. Ejemplo: si tienes 30 items, activas el CAB, seleccionas el campo 3 y el campo 28, se va a caer el app. Va a dar una excepción de puntero nulo. Si no me creen hagan la prueba con sólo 10 filas, eso sí, que sean lo suficientemente grandes para tener que bajar con el ScrollBar xq no caben en la pantalla. Bueno, hasta el momento es como me ha salido así, quizás esté equivocado.

            Hice esto pero no sé cómo hacer un desmarcado masivo:

            @Override
            public void onItemSelected(AdapterView parent, View view, int position, long id) {

            if (check){
            view.setBackgroundColor(Color.CYAN);
            vistas.add(view);
            }
            else {
            view.setBackgroundColor(Color.TRANSPARENT);
            for (int i=0;i<=vistas.size();i++){
            if (vistas.get(i).toString().equals(v.toString())){
            vistas.remove(i);
            break;
            }
            }
            }

            v = view;
            }

            @Override
            public void onNothingSelected(AdapterView parent) {
            }
            });

            Pero no he logrado desmarcarlos cuando llama a este método:

            @Override
            public void onDestroyActionMode(ActionMode mode) {
            // Here you can make any necessary updates to the activity when
            // the CAB is removed. By default, selected items are deselected/unchecked.
            }

          2. Si necesitas un listado grande, te recomiendo que añadas un HashMap o un ArrayList nuevo; que parejo con el ArrayList del Adaptador (puedes modificar el adaptador para esto), guarde el estado de pulsado o no y que cambie el fondo de la entrada del listado a la que se refresca en pantalla.

          3. Buenas tardes!

            Gracias por la ayuda, pero ya había intentado guardar los views o los campos seleccionados y no me resultaba. Bueno, al menos no a mí. Así que busqué y busqué y al final hice esto:

            En el getView de la clase BaseAdapter personalizada:

            view.setBackgroundColor(Color.TRANSPARENT);

            if (mSelection.contains(posicion)) {
            view.setBackgroundColor(Color.BLUE); // color when selected
            }

            En el Activity:

            @Override
            public void onItemCheckedStateChanged(ActionMode mode, int position,
            long id, boolean checked) {

            if (checked){
            adapter.setNewSelection(position);
            }
            else{
            adapter.removeSelection(position);
            }

            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {
            // Here you can make any necessary updates to the activity when
            // the CAB is removed. By default, selected items are deselected/unchecked.

            adapter.clearSelection();
            }

            Pura vida!

  77. Hola Ramon.

    soy novato en esto de Android, tengo un nivel bastante basico.
    He realizado tu ejemplo de lista adaptando un poco a la aplicacion que quiero hacer (una lista de compra), es decir solo mostrare dos textview en mi listado uno con el nombre del producto y otro con el importe, tu ejemplo adaptando esto me a salido perfectamente, lo que me gustaria implementar ahora, es la entrada manual de estos datos, por ejemplo con un textedit arriba y dos boton para agregar un componente a la lista con un importe a 0,00 y otro para resetear toda la lista y al presionar sobre uno de los componente de la lista que te pida el valor y actualizar el textview del componente con el nuevo valor de importe.
    tambien me gustaria poder borrar los componentes que ya no necesito (si no es dificil desplazando el dedo por encima).
    y tambien me gustaria que la lista se valla guardando en fichero para cuando vuelva arrancar la aplicacion que cargue los componentes del listado de nuevo (creo que para eso se deveria crear el fichero al arrancar por primera vez el programa, verdad?).

    voy tirando de ejemplos pero muchas cosas no me salen, a ver si me podriais ayudar en esto porfavor.

    Saludos.
    Javier,,

    1. Buenas Javier,

      necesitas muchas cosas que hay que ir implementando poco a poco. Te recomiendo que empieces con los botones que es lo fácil. De los botones puedes ver algunos ejemplos en http://jarroba.com/expansion-listview/. Para eliminar elementos te valdría con actualizar el ArrayList del adaptador (o bien añadirle un método que elimine elementos y llame a notifydatasetchanged() ). Lo del desplazamiento del dedo, hay que tratar con animaciones y gestos, no es que sea difícil, pero requiere trabajo y mucho código, con lo que te animo a intentarlo para aprender 😀

      1. Gracias Ramon.

        he implementado el edittext y dos botones, uno para agregar informacion a la lista (el codigo lo he puesto justamente despues del lista.setAdapter… pero tengo un problemilla que no encuentro el comando para actualizar la lista, y solo me aparece el nuevo objeto cuando hay un cambio en la pantalla como cuando le doy al boton atras para esconder el teclado):

        botonADD = (Button)findViewById(R.id.botonADD);
        botonADD.setOnClickListener(new OnClickListener (){

        @Override
        public void onClick(View v) {

        datos.add(new Lista_entrada(InpName.getText().toString(),”0.00″));

        }
        });

        el otro boton esta definido igual y es para borrar toda la lista (pero no se si se puede hacer), para empezar de nuevo.

        1. El refresco es por no llamar a notifydatasetchanged() desde el adaptador (puedes llamarlo después de añadir datos a la lista del modo miAdaptador.notifydatasetchanged() ). Para el borrado puedes hacerlo sin problemas igual, lo que te comenté previamente, puedes o modificando el adaptador, o intercambiándolo entero, aquí es decidirse 🙂

  78. Mu buenas,
    ¡impresionante aporte!

    Lástima que no este explicado adaptado a JSON.

    Por necesidades de mi trabajo y ya que soy un poco manitas necesito crear una aplicacion parecida a esta pero para clientes.

    Tengo resuelto el apartado de login nediante json pero solo me faltava encontrar el listview pero veo que no esta adaptado a JSOn.

    ¿Como tendria que hacerlo?

    Muchas gracias de antemano.

    Jordi.

    1. Buenas Jordi,

      no lo tienes complicado para adaptarlo a JSON. JSON es una representación de objetos, con lo que tienes que convertir cada uno de esos objetos a un elemento del listado (tienes un ejemplo de como hacerlo aquí http://developer.android.com/reference/android/util/JsonReader.html), y cada uno de estos añadirlo al ArrayList que pasaremos al adaptador. Fácil y sencillo, te dejo a practicar esto, ya verás como en unas cuantas líneas de código lo tienes hecho 🙂

      1. Estava trabaando con androis studio, por lo que he visto tengo muchos problemas para adaptar cosas que no son compatibles, pero encambio me pasa lo mismo con Eclipse. Cuando este coje una aplicacion de Android marca muchos errores y coje mal los valores.

        Tendre que empezar de 0 con Eclipse para adaptar tu aplicacion.

        PD. tu aplicacioin se me detiene cuando intento ejecutarla en un telefono android minis4. ¿Porque?

        1. Buenas Jordi,

          Es un poco extraño que te fallen los dos entornos de desarrollo con el mismo código y también en el móvil, todo apunta a que hay en el código que provoca el error. Repasa que no haya nada mal copiado en el código (puedes descargarte el código completo al final del artículo).

          1. Al final he solucionado la parte de los programas pero:

            Cuando cojo mi programa diseñado por mi y funcionando al 100% y le miro de introducir tus aportes me viene un error y se detiene la aplicación.

            te comento:

            Mi apli es un simple login con json y al autentificarse se redirige a un layout diferente. uso esta parte de java para hacerlo.

            protected void onPostExecute(String result) {

            pDialog.dismiss();//ocultamos progess dialog.
            Log.e(“onPostExecute=”,””+result);

            if (result.equals(“ok”)){

            Intent i=new Intent(Login.this, HiScreen.class);
            i.putExtra(“user”,user);
            startActivity(i);

            }else{
            err_login();
            }

            Yo lo que interpreto que tengo que hacer para que redirija a tu pagina es cambiar solamente el .class (HiScreen.class) por tu java (MainActivity.class)

            pero cuando de autentifica el login y tiene que pasar a tu layout listado de cierra la aplicacion. donde esta mi error??

            Jordi

          2. El código que has adjuntado parece correcto. Pueden ser muchas cosas, pero revisaría si has declarado en el AndroidManifest.xml a la Activity nueva, pues si te falla al lanzar la Activity huele a este típico olvido. Si no fuera esto mira en el log, vete al error en rojo que salga con más texto, y cópianos la primera línea para ver que puede estar fallando y poder ayudarte.

  79. Hola, mis felicitaciones por este sitio que tiene información excelente. Quisiera exponer una duda, he creado una aplicación para mostrar fotos a modo de álbum digital, me funciona perfecto, sin embargo, quiero tomar las imágenes de la SDCARD, puesto que al ser mas de 15 fotos, la aplicacion se hace muy pesada porque se encuentran las imágenes almacenadas en el folder drawable; ya he buscado información y veo que requiere utilizar el getExternalExternalStorage para controlar el estado de la memoria. Ya hice pruebas pero no logro controlar el nombre del directorio, el nombre del archivo y pasarlo al contenedor para mostrarlo en la pantalla. ¿Me puedes orientar por favor como lograrlo?
    Saludos

    1. Buenas Mario,

      Es bueno saber que nuestros artículos son interesantes, seguiremos esforzándonos es proporcionar más contenido de calidad 🙂

      En respuesta a tu pregunta, para guardar cualquier archivo en memoria te valdría con usar (dónde “FICHERO” es un String con el nombre del fichero, “escribir” es el archivo a guardar en disco y “tamanioContenido” el tamaño de “escribir”):

      FileOutputStream mStreamSalida = openFileOutput(FICHERO, Context.MODE_PRIVATE);
      mStreamSalida.write(escribir.getBytes(), 0, tamanioContenido);

      Para volverlo a leer, lo que tienes que hacer es escanear la tarjeta de memoria con MediaScanner (http://developer.android.com/reference/android/media/MediaScannerConnection.html) para que esté disponible el fichero, y leer el fichero a la inversa (en vez de con FileOutputStream con FileInputStream ).

  80. Amigos me ha sido de mucha utilidad su ejemplo, pero tengo una duda, adapte el ejemplo y ahora leo objetos del json y dichos objetos tienen un atributo fotografia en base64, lo transformo y lo dejo como bitmap. El problema que me surge es que algunas fotos pueden estar null, en ese caso debo colocar una foto default que guarde en una carpeta llamada drawable, mi problema es que no se como obtener esa foto y transformarla a bitmap, espero me puedan ayudar, gracias

  81. Hola, primero enhorabuena por vuestra web! una consulta, soy novato en Android: ¿como podría insertar datos desde una segunda actividad?
    Muchas gracias.
    Saludos

  82. Buenas tardes,

    Antes que nada, felicidades por vuestros tutoriales ya que son de gran ayuda.
    Me gustaría saber cómo puedo rellenar un listview desde un asynctask ya que debo obtener datos de internet mediante JSON y, si el tiempo de respuesta es elevado, la aplicación fallaría.
    Cómo puedo devolver un ArrayList desde en método doInBackground() ???

    Adjunto el código para ver si me podéis ayudar.

    @Override
    protected String[][] doInBackground(Void… params) {

    //Preparo el GET
    HttpClient httpClient = new DefaultHttpClient();
    HttpGet del = new HttpGet(obten_Datos);

    del.setHeader(“content-type”,”application/json”);

    try{

    HttpResponse resp=httpClient.execute(del);
    String respStr=EntityUtils.toString(resp.getEntity());

    JSONArray respJSON=new JSONArray(respStr);
    String[] datos_pinNumber = new String[respJSON.length()];
    String[] datos_pinDescription = new String[respJSON.length()];
    String[] datos_pinStatus = new String[respJSON.length()];

    ArrayList datos = new ArrayList();

    for ( i=0;i<respJSON.length();i++){

    JSONObject obj = respJSON.getJSONObject(i);

    String description=obj.getString("description");
    String estado=obj.getString("estado");

    // datosDescription[i]=description;
    // datos_estado[i]=estado;

    if (estado=="1"){
    datos.add(new Lista_entrada(R.drawable.on,Description));
    }
    else{
    datos.add(new Lista_entrada(R.drawable.off,Description));
    }

    i++;
    }

    }

    }

    El código está incompleto ya que estoy atascado.
    Muchas gracias.
    Un saludo,

    Juan

  83. Hola. 🙂
    Gracias por la explicación 😀 está bien clara y entendible, soy nueva en este lenguaje y nuestro maestro no es precisamente alguien que sabe de esta materia, así que queria saber como puedo migrar los datos de las aves a una DataBase?
    Es decir que las características de las aves se almacenen en una base de datos y al momento de dar clic al listview muestre los datos de la DB?
    Ayuda porfa 🙁

    1. Muy buenas Silvia,

      De momento no tenemos ningún tutorial para base de datos, pero te recomiendo que empieces por aquí: http://developer.android.com/guide/topics/data/data-storage.html#db. Tienes un ejemplo completo en http://developer.android.com/training/notepad/index.html 🙂

      Muchos ánimos con Android, te puedo asegurar que es un mundo apasionante en la que aprenderás un montón de cosas y siempre con la última tecnología 😀

  84. que pasada de articulo !!!!!! y de web!!!
    internet, y el mundo ,necesita más gente como vosotros.
    Muchas gracias de verdad de la buena!!!

  85. Hola, ya tengo parte de mi proyecto funcionando con Fragmentos como paginadores y en cada una cargo una lista. El proyecto que estoy realizando es una encuesta ne la que tengo por ejemplo Capitulo 1 y en ella debo capturar unos datos y Capitulo 2 son otros datos. Mi lista se compo es ahora de dos imagenes, la primera que esta en la parte izquierda donde cargo una imagen que me identifique si el campo a capturar es obligatorio o no, el texto superior lo utilizo para las preguntas y el texto de abajo lo voy a utilizar para mostrar el dato que seleccionaron o que digitaron y al fina de la lista va otra imagen (Una caja vacia que indica que no se ha caprurado el dato y otra caja chequeada que identifica que el dato ya esta capturado). Que me aconsejan para yo poder mantener esos datos que he capturado y como se y en que momento se refresca la lista para que cuando pase a la siguiente pagina o capitulo no se me pieda dicha información. Me aconsejan manejar bases de datos y almacenar la información en una tabla temporal. Agradezco a ustedes sus comentarios al respecto.

    1. Eso depende un poco de la cantidad de datos que manejes, y si realmente los quieres persistir. Si tienes que controlar muchos datos cuyos atributos se repiten (por ejemplo un listado de pájaros con cada uno un nombre y cada uno una descripción) la base de datos es la mejor opción. Si solo quieres persistir una pequeña cantidad de datos sin complicarte demasiado, puedes usar SharedPreferences. Y si no quieres mantener los datos en memoria, solo pasarlos entre ventanas, te recomiendo que los pases por el Intent como Extras. De momento no tenemos artículo que describa esto, pero puedes consultar en la documentación oficial, en la que vienen ejemplos: http://developer.android.com/guide/topics/data/data-storage.html

      Comentar que hemos abierto un foro en http://jarroba.com/foro/ para resolver más cómodamente cualquier tipo de dudas (el sistema de comentarios se queda pequeño) sobre Android o cualquier otra materia de las que tratamos 😉

      1. Gracias por la respuesta, creo que voy a manejar base de datos ya que son cerca de 60 preguntas. Pero me queda la duda es en que parte integro la consulta de cada uno de los item de la lista para cargar cierta imagen por ejemplo el de mostrar que en ese item ya se digito un dato. Porque he realizado una prueba por ejemplo de cambiar la imagen cuando dan click sobre un item en lista.setOnItemClickListener con este código:

        ImageView imagen_cambioestado = (ImageView) view.findViewById(R.id.imageView_imagen);
        imagen_cambioestado.setImageResource(R.drawable.ef_checked);

        lo hace pero si paso a otro fragmento y regreso al primero vuelve y me sale la primera imagen en todos los item, asumo que vuelve y me pinta la lista.

          1. Estuve mirando lo del ejemplo que me dices del ciclo de vida del Fragment, pero ello manetiene el recuerdo de variables en memoria, y haciendo otras averiguaciones encontre que si uno esta corto de memoria en el equipo el sistema Android tal vez no haga el llamado al metodo onSaveInstanceState() peerderia esos datos y recomiendan el uso de onPause() y onResume(). 1000 Gracias… Ya otra duda tratare de utilizar el Foro.

  86. Excelente Tutorial, me ha funcionado bien. Pero me gustaría saber como puedo colocar una lista dentro de un Fragmento. Tengo una Activity con Tapages que se extiende de FragmentActivity y el códgio donde realizo el llamado a la activity que quiero de la lista es;

    public static class LaunchpadUbicacionFragment extends Fragment {

    // Agregado para Manejar la lista
    private ListView lista;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.activity_ubic, container, false);

    return rootView;
    }
    }

    Como hago para unificar este ListView, de este tutorial me funciona si lo trabajo solo pero no se como hacer el montaje sobre el Fragment. Existe un ejemplo que se peda ver como funcionarian los dos tanto Fragment como Listview. Trate de colocar el código del Mainactivity de este tutorial pero al momento de ver la lista, me sale para unos los iconos y para otros registros ya no salen los iconos ni los nombres de los animales. Agradezco a ustedes la colaboración, el trabajo que estoy haciendo lo tengo es en Android Studio.

      1. Gracias Ramón, lo estoy revisando y si ya habia realizado algo parecido en una Tablet solo que de lista mostraba unas Fincas y cuando seleccionaban uno de ellos en otro Fragmento mostraba la ubicación con Google Maps, pero ello hace rato y con versiones viejitas de android. Tambien lo de el paginador lo habia realizado con la opción de Tab pero ahora para versiones ultimas de Android ya no me funciono, y por ello busque un ejemplo de manegar paginadores pues no quiero mostrar la información en la misma Activity (ya que es una aplicación para celulares y no Tablets), lo que estoy realizando es como una Encuesta y esta depende de Capitulos y para ello te trato de colocar la imagen que he capturado donde salen tres pestañas una de ubicación, otra de Caracterización y otra de observación y he montado lo del aplicativo de Listview que explicas aca y en la imagen veras que es lo que me pasó. Este es el link. http://algodon.minagricultura.gov.co/images/android/Aplicacion_Android.png , voy a tratar de ver el tutorial de Fragments a ver como me va e identificar como puedo hacer el llamado de la Activity Principal del Listview.

          1. Gracias Ramón, he solucionado mi problema que te habia comentado de cargar la MainActivity de este tutorial, mi problema radicaba en el setAdapter allí en lugar de This deberia era hacer el llamado de mi Fragment así:

            El llamado anterior era

            lista.setAdapter(new Lista_adaptador(this, R.layout.entrada, datos){

            y mi cambio quedó así:

            lista.setAdapter(new Lista_adaptador(rootView.getContext(), R.layout.entrada, datos) {

            Gracias…

  87. Hola primeramente felicitaciones por el tutorial esta muy bueno ya lo hize correr … soy nuevo en esto y me gustaria que me ayudes a listar desde web service el cual tiene 4 columnas y solo utilizo 2 que son asunto y descripcion… este es mi codigo me puedes corregir no me corre 🙁

    public class MainActivity extends Activity {

    private ProgressDialog pd;
    private ListView lista;
    private Context context;
    private Button boton1;
    Notificacion[] listaNotificacion;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);context=this;
    setContentView(R.layout.listado);
    new DownloadTask1().execute(“”);
    pd = ProgressDialog.show(context, “Por favor espere”,”Enviando info a notificaciones”, true, false);
    }
    private class DownloadTask1 extends AsyncTask
    {
    protected Integer doInBackground(String… args) {
    CargarDatosWS ws = new CargarDatosWS(); // de aqui los rescato de mi webservice
    listaNotificacion=ws.listar1();
    return 1;
    }
    protected void onPostExecute(Object result) {
    //Se elimina la pantalla de por favor espere.
    pd.dismiss();
    ArrayList datos = new ArrayList();

    final String[] datos1 = new String[listaNotificacion.length];
    final String[] datos2 = new String[listaNotificacion.length];

    for(int i=0; i<listaNotificacion.length; i++)
    {
    datos1[i] = listaNotificacion[i].asunto; //cadena
    datos2[i] = listaNotificacion[i].descripnion; //cadena
    datos.add(new Lista_entrada(R.drawable.descarga, datos1[i], datos2[i]));

    }

    lista = (ListView) findViewById(R.id.ListView_listado);
    lista.setAdapter(new Lista_adaptador(MainActivity.this, R.layout.entrada, datos){
    @Override
    public void onEntrada(Object entrada, View view) {
    if (entrada != null) {
    TextView texto_superior_entrada = (TextView) view.findViewById(R.id.textView_asunto);
    if (texto_superior_entrada != null)
    texto_superior_entrada.setText(((Lista_entrada) entrada).get_textoEncima());

    TextView texto_inferior_entrada = (TextView) view.findViewById(R.id.textView_descripcion);
    if (texto_inferior_entrada != null)
    texto_inferior_entrada.setText(((Lista_entrada) entrada).get_textoDebajo());

    ImageView imagen_entrada = (ImageView) view.findViewById(R.id.imageView_imagen);
    if (imagen_entrada != null)
    imagen_entrada.setImageResource(((Lista_entrada) entrada).get_idImagen());
    }
    }
    });

    lista.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView pariente, View view, int posicion, long id) {
    Lista_entrada elegido = (Lista_entrada) pariente.getItemAtPosition(posicion);

    CharSequence texto = “Seleccionado: ” + elegido.get_textoDebajo();
    Toast toast = Toast.makeText(MainActivity.this, texto, Toast.LENGTH_LONG);
    toast.show();
    }
    });

    }

    }
    }

    1. Muy buenas Dario,

      he analizado tu código y no veo nada que pueda estar mal así de primeras. Lo tienes bien configurado. Comprueba que le lleguen datos al servicio web (es decir, que el ArrayList tenga datos). De todas maneras para saber que error te está dando lo mejor es que nos copies el error del log.

  88. Hola a tod@s!!!

    Al cargar los elementos en el ListView y lo ejecuto, no puedo pulsarlos hasta que no muevo el scroll del ListView, me entendeis??

    Funciona perfectamente pero tengo que bajar y subir los elementos como para que se refresquen…..es raro???
    espero que me podais ayudar!!!

    Muchas gracias!!!

    1. Buenas Luisge, un poco raro sí que es, pero peores cosas se han visto 🙂

      Sin ver el código del XML donde pones el listado es complicado, pues suele venir por una mala configuración de los Layout. Los errores pueden venir como que el ListView no sea el elemento raíz (esto aveces es deseable, pero da problemas), que esté dentro de un scrollview, que tenga algún elemento android:clickable=”false” o un android:focusable=”false”, etc.

      Si nos das algún dato más podremos ayudarte mejor.

  89. Viejo sos la hostia! gracias por tutorial tan bueno, tan explicado, tan amoroso, tan lindo, tan precioso, y tan tan… gracias totales! XD jaja

  90. Saludos y muchas felicidades por tomarte tu tiempo en explicar paso a paso como crear una ListView personalizada con imagen.

    Justo lo que andaba buscando y después de haber leído el tutorial y seguido los pasos me funcionó a la perfección, ya solo falta que añade a mi proyecto los otros activities que seguirán al dar clic a un Item de la lista.

    Espero que continues con más tutoriales de android.

    Atte. Charls

  91. Tengo una duda quiero que al presionar un botonque se encuentra en Listado.xml pueda agregar un nuevo elemento a la llista y esta se actulize obviamente
    me podrias dar una breve explicacion de como aplicarlo en tu codigo porfavor

    1. Buenas Erick,
      para hacer lo que necesitas se necesitaría o bien crear un adaptador que soportase añadir (el de este artículo está diseñado para crearse una vez y no cambiarse). O puedes usar este adaptador creándolo de nuevo cada vez que necesites actualizar el listado, es decir, volviendo a llamar a lista.setAdapter() pesándole el nuevo adaptador con los cambios.

  92. Wenas, lo primero agradecer el tutorial. El tema de arrys siempre me ha costado, y para mi es de lo mas dificil. A pesar de ello esta muy bien explicado
    Ahora viene el problema 🙁
    Cuando lo ejecuto con eclipse, me sale este error: “Unfortunately, Listado has stopped”. He hecho pruebas, y me he dado cuenta que el programa va bien si seleccionas las primeras imagenes (pinchas en buho y te sale su descripcion); pero el programa peta cuando intentas bajar y seleccionar el resto de animales (loro, pavo pingüino)

    1. Muy buenas Richel,

      el programa es de ejemplo con las imágenes que ocupan bastante. Prueba a aumentar la memoria del emulador para que no expulse a la app por falta de memoria.

      Cuando se hacen bien los listados con imágenes, lo que hay que hacer es cachear las imágenes (esto requiere mucho más código y complejidad, en este tuturial lo hacemos básico para poder crear cualquier tipo de listado y que sea sencillo de entender).

      Mucho ánimo con el aprendizaje de arrays, ya verás como en poco serás toda una experta 🙂

      1. Wenas de nuevo, he probado a darle mas memoria pero seguia pasando lo mismo. He optado por pasarlo a mi movil (asi he aprendido ocmo se hacia), y funciona bien 🙂
        Muchas gracias por todo, seguire leyendo el resto de tutoriales
        saludos

  93. Hola!

    Lo primero, debo felicitarte por el tutorial, es de los más claros que he visto por la red.

    He estado intentando modificar el adaptador que habéis publicado para que sea posible eliminar entradas de la lista al pulsar otras, es decir, imaginemos que pulsemos la entrada número 1, y que al hacerlo se eliminan las entradas 4 y 5 (o se muestran otros elementos ocultos).

    Si me pudieras dar alguna indicación sobre como resolver esto, te estaría muy agradecido!

    Muchas gracias de antemano,

    Ignacio

    1. Hola Igancio,

      para poder modificar el listado añadiéndole y eliminándole elementos cuando se desee, es necesario poder instanciar el adaptador (el adaptador que presentamos aquí no es instanciable, diseñado así para que sea más didáctico y fácilmente usable en la mayoría de los casos). Tienes que modificar el adaptador, que no sea abstracto, y que lo puedas instanciar, añadiéndole métodos para poder modificar a petición el arrayList interno del adaptador. Es un poco complejo explicar esto, por ello estamos preparando un tutorial para los listados complejos que intentaremos publicar lo antes posible.

      Y gracias por las felicitaciones, seguiremos esforzándonos en cada tutorial 🙂

  94. Buenas, me parece muy interesante el articulo, pero no soy capaz de hacerlo funcionar en Android Studio… Me deja de funcionar la R, pero lo que no puedo hacer nada…
    También sería interesante adaptar este mismo ejemplo cargando los datos de un XML local y de un XML online, por ejemplo en Dropbox o en Google Drive….
    Para los que estamos empezando sería de gran ayuda poder analizar en profundidad código que veamos que funciona, porque la mayoría, una vez lo montas ni siquiera funciona….

    Un saludo,

    David.

    1. Hola David,
      De momento no te recomiendo que uses Android Studio, está en beta y no hay muchas o ninguna solución para ciertos problemas, y si estás empezando con Android mejor no liar las cosas. Usa mejor Eclipse (mira en http://jarroba.com/instalar-el-sdk-de-android-y-vincularlo-con-eclipse/)

      De todas maneras, aunque el artículo disponga para su explicación del código completo, siempre se puede dar el caso de errar al copiarlo. A razón de que hemos sido participes de lo molesto que es el no funcionamiento del código puesto en los tutoriales que se encuentran por Internet; dejamos siempre preparado, montado y funcionando el proyecto entero para descargar al final del artículo. Pruébalo y nos comentas 🙂

      Y tu sugerencia nos parece muy interesante, tomamos nota para un futuro artículo.

  95. felicidades por el tutorial les quedo excelente

    directo con mi pregunta
    fui copiando sus codigos por partes y el programa me funciona con la excepcion q en el listview solo aparece un objeto con los valores q le asigno, si meto mas aparecen el molde dentro del lstview vacios
    quisiera su ayuda amigos

    1. Gracias Oscar por los ánimos 🙂
      Respecto a tu pregunta, es complicado sin ver el código, pero parece que algo no se está pasando bien al adaptador. Revisa el tutorial o descarga el programa completo al final del mismo para compararlo con lo que has hecho.
      Cualquier otra cosa no dudes en consultarnos.

      1. Gracias por responder!!!
        quisiera saber si me podes ayudar estoy intentado calcular los dias entre dos fechas en android?
        gracias de antemano

  96. Este tuo es casi justo lo que necesito, solo que los datos lo necesito traer desde una base de datos en SQLite, tengo todo el CRUD para ello, solo quiero que al mostrar los muestre con de esta forma, imagen y texto, tendreas algun tuto mas especifico, ya revise tu otro aporte donde das mas info de como implementar los listview pero aun me quedan en el aire.

    Saludos.

    1. Buenas Joe,

      De momento no tenemos ningún tutorial de SQLite para Android 🙁

      Si ya tienes experiencia, lo que necesitas hacer es realizar la consulta y en cada iteración del puntero del cursor llamar a “datos.add()” para ir añadiendo al arrayList los datos que estaban previamente almacenados en la base de datos.

  97. Hola primero por agradecer que compartes tus conocimientos y luego me gustaría si me puedes guiar con un caso que estoy desarrollando,
    1. en una activity selecciono por ejemplo un producto de una lista,

    2. luego me pasa a otra actividad en la cual puedo modificar por ejemplo precio, nombre y hay un botón añadir que carga la nueva

    3. Actividad que es un listview personalizado que es donde se presenta la venta añadida, en esta actividad tengo un botón para seguir añadiendo productos que me vuelve a la actividad 1.

    (y aqui es mi problema pues no se como guardar el arraylist con las ventas ya hechas y agregar la nueva venta para mostrarlas en el listview personalizado.)

    No se si me doy a entender y si me entiendes me puedes guiar?

    Gracias desde ya.

    Saludos

    1. Buenas Dielo,

      Vamos a intentar ayudarte 😉

      Prueba para pasar datos entre actividades tienes varias maneras (puedes consultarlas en: http://developer.android.com/guide/topics/data/data-storage.html). Para listas dinámicas recomiendo personalmente usar base de datos (mantiene persistencia de datos, las búsquedas son más rápidas, si manejas bien SQL se simplifican los filtros, etc). Otra opción, es usar un singleton para pasar formado el objeto arraylist entre actividades (en el ejemplo lo hemos llamado ArrayList<Lista_entrada> datos). También puedes echar un ojo a: http://developer.android.com/guide/faq/framework.html#3

      1. Hola logre solucionar colocando como public static al arraylist de objetos ahí guarda los registros pues ya que no necesito pasar a otras actividades mi array de objetos. No quize usar sqlite en este punto pues luego de confirmar los productos los almaceno en una tabla y en la primera actividad ya abro la bd creo era mucho forzar la app.
        Gracias por la orientación

        Saludos

  98. hola gracias por la aportacion me ha ayudado bastante e impemente asyntask para refrescar mi lista solo tengo un probema q no le he buscado solucion es como mantenerme en la ultima posicion ya que al cargar mi listview cn los siguientes 10 registros me regresa al primer item y tengo q volver a recorrer la lista

      1. Gracias pr responder la verdad l habia visto e mensaje he logrado resolver ahora tengo una duda lo que pasa esquq obtengo los datos a travez de json que me debe traer la url del mensaje y estoy usando este asynk task q encontre tratare de ser breve en a funcion donde uso el on entrada que modifique separandolo un poco asi
        /*************** primera tarea asincrona que carga los primeros 10 registros solo es una parte donde recorro el onEntrada***********////////
        adaptador = new Lista_adaptador(SecondActivity.this, R.layout.entrada, datos){
        @Override
        public void onEntrada(Object entrada, View view) {

        TextView texto_superior_entrada = (TextView) view.findViewById(R.id.textView_superior);
        texto_superior_entrada.setText(((Lista_entrada) entrada).get_textoEncima());

        TextView texto_inferior_entrada = (TextView) view.findViewById(R.id.textView_inferior);
        texto_inferior_entrada.setText(((Lista_entrada) entrada).get_textoDebajo());

        ImageView imagen_entrada = (ImageView) view.findViewById(R.id.imageView_imagen);
        //la siguiente linea me actualiza la imagen que tenga en los recursos que es lo que quiero cambiar
        //imagen_entrada.setImageResource(((Lista_entrada) entrada).get_idImagen());
        //pretendo que en ves de usar una imgen de los recursos descargarla de internet y actualizarla usando un asyntask
        imagen_entrada.setTag(“http://elbauldelprogramador.com/wp-content/uploads/2013/07/xiconoAndroid.png.pagespeed.ic.m7N5dGWYmc.png”);
        DownloadImagesTask AsynKImage = new DownloadImagesTask();
        AsynKImage.execute(imagen_entrada);
        }
        };

        //actuaizamos la lista que contiene el listview de referencia
        lista.setAdapter(adaptador);

        /**********************************************
        //tarea asincrona que utilizo para descargar la imagen y actualizar el imagenView pasandole como parametro la imgView donde asignare la imagen descargada
        public class DownloadImagesTask extends AsyncTask {

        ImageView imageView = null;

        @Override
        protected Bitmap doInBackground(ImageView… imageViews) {
        this.imageView = imageViews[0];
        return download_Image((String)imageView.getTag());
        }

        @Override
        protected void onPostExecute(Bitmap result) {
        this.imageView.setImageBitmap(result);
        }

        private Bitmap download_Image(String url) {
        //—————————————————
        Bitmap bm = null;
        try {
        URL aURL = new URL(url);
        URLConnection conn = aURL.openConnection();
        conn.connect();
        InputStream is = conn.getInputStream();
        BufferedInputStream bis = new BufferedInputStream(is);
        bm = BitmapFactory.decodeStream(bis);
        bis.close();
        is.close();
        } catch (IOException e) {
        Log.e(“Hub”,”Error getting the image from server : ” + e.getMessage().toString());
        }
        return bm;
        //—————————————————
        }

        }

        1. me descarga a imagen pero aplica la misma imagen para cada eemento de a lista l comprobe con el otro asyntask que me carga los siguientes 10 pero con tra url de la imagen

        2. No ejecutes el AsyncTask en el onEntrada, pues se ejecutará en cada entrada de la lista. onEntrada solo está para asignar los recursos a las views.

          Lo que tienes que hacer es modificar el handler “Lista_entrada”, y en vez de pedir un identificador de recurso para la imagen, debes de guardar un Bitmap descargado (por ejemplo). Por lo que el “datos.add(…)”, sería bueno que lo llamaras al terminar de descargarse cada imagen, para ir formando el arrayList sin retrasos y por tener una variable para guardar las imágenes. Y al terminar con el Asyntask formar la lista, así ya lo tendrías 😉

          1. Efectivamente es lo que he pensado hacer que a momento de obtener e objeto en json me vaya descargando las imagenes en una tarea asincrona pero en e asyntask que manejo necesita una imgView ya ligada a uno de recursos y lo que queria saber es como devover el resultado de un asyntask a una variable mas bien retornar e bitmap y asignarselo al objeto con la clase lista entrada x que si no tendria q esperar a q se carguen las imagenes de las proximas 10 entradas

          2. Para cargar las imágenes después de descargarlas te recomiendo que hagas algo así en el onEntrada, claro que adaptándolo a tu código:
            ImageView imagen = (ImageView) view.findViewById(R.id.imagenPorDefecto);
            funcion_para_pasar_la_ImageView_al_segundo_plano(imagen);

            Lo explico, en el onEntrada conoces cual es el ImageView, con lo que ya sabes donde va a ir la imagen en cuanto se descargue. Solo tienes que pasárselo al AsynTask. Para que cuando termine de descargar la imagen para esta ImageView, cambie la imagen por defecto por la descargada. Esto lo puedes hacer con:
            imagen.setImageBitmap(bitmap);

        3. Ya entendi la idea el problema esque cuando hice lo que me dijiste la primera ves me actualizo una imagen para todos entonces al hacer scroll para cargar los proximos 10 ya no me toma a otra url ahora cambiandolo un poco queria saber si es posible hacer que lo cargue internamente ya que no entendido muy bien la funcion del asyntask por ejemplo y recorro mis 10 primeros registros de json y en cada registro ejecuto un nuevo asyntask que me hace esto? me genera un hilo por cada registro? si es asi como podria identificar que hilo pertenece a que imagenview

          1. Sí, te generaría un hilo por cada registro.

            Haces muy bien al usar la multitaréa, pero mejor ejecuta una sola vez el asyntask (tendrás un hilo en segundo plano y el principal). Y en el doInBackground haz la conexión al servidor para recuperar el json. Entonces, al terminar (en el onPostExecute) o mientras se siguen recuperando elementos (en el onProgressUpdate) ve añadiendo el contenido de las entradas.

  99. Hola, he copiado todo tal como en tu tutorial pero también me lanza nullpointerException en la linea de

    lista.setAdapter(new Lista_adaptador(this, R.layout.entrada, datos) …y sí he declarado lista como variable global. No entiendo por qué :/

    1. Buenas Ana,

      El nullpointerException puede venir por muchos motivos, uno es el que comentas, y otros pueden ser que los parámetros del constructor tengan algún null. Sin ver el código es complicado decir exactamente lo que es.

      Te recomiendo que descargues el proyecto entero, al finalizar el tutorial tienes el link, lo importes, pruebes y compares código para entender donde está fallando.

  100. Hola Ramon, tengo una consulta, deseo pintar algunas filas del listView pero que cumplan una condicion especifica, como lo haría?. Espero tu respuesta gracias!

    1. Buenas DianA,

      Cuando te refieres a pintar a que te refieres exactamente. Por el contexto de la frase no sé si te refieres al Canvas, a la base de datos, al fondo de las Views,… te agradecería un poco más de precisión para responderte correctamente 🙂

  101. Hola que tal, estoy utilizando tu codigo muy bueno la verdad aunque yo lo estoy utilisando para una lista de alumnos y en la parte de la foto es dode me estoy atorango, ya que necesito agarrar la foto de la memoria externa, es decir, de la direecion “photoPath = Environment.getExternalStorageDirectory() + “/DCIM/Camera/foto.jpg” ” pero e intentado hacer lo siguiente:

    File imgFile = new File(b);
    if(imgFile.exists());
    {
    Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
    ImageView myImage = (ImageView) findViewById(R.id.imageView1);
    myImage.setImageBitmap(myBitmap);

    }
    datos.add(new Lista_entrada(myBitmap, a, “”));

    donde a es el nombre del alumno y b de ariba es donde me traigo la direccion pero me marca error, saludos.

    1. Buenas Juan José,

      Comprueba a ver si en Entrada estás recogiendo un Bitmap y no un recurso (un entero que normalmente empieza con R. … ), pues en el tutorial recogemos un recurso.

      Sino, si nos pones del log el error podremos ayudarte más.

      Nos cuentas a ver 🙂

  102. Muy buenas, me parece excelente tú comenatrio, soy neófito ena ndroid y necesito saber si puedes ayudarme.
    Tengo un sistema en php donde se crean encuestas y s eaplcian, deseo poder aplicarlas en ANDROID el problema es que nunca serán dos encuestas iguales entonces toda la parte visual (layout en xml) debe poder ser de manera dinámica, la intención es leer de la base de datos el número de preguntas, el tipo de respuestas que se requiere y en base a cada tipo der espuesta irt creando los botones de radio, las listas, los botones de selección.
    ¿Se puede esto en android?
    ¿tendrás por casualidad algún ejemplo o algo que me sirva de guía?

    De anetmano muchas gracias

    1. Buenas Marvin Aguilar,

      La respuesta a si se puede es afirmativa. Puedes generar un PHP que devuelva un JSON con los datos que necesites. Y en Android, hacer la conexión a este PHP y que convierta el JSON a un array de objetos. Luego te quedaría tomar este array de objetos con los datos y recorrerlo, para montar las filas de la lista.

      Seguro que has notado que tiene bastante chicha, no es difícil, pero requiere bastante código. Tengo intención de sacar algunos tutoriales más avanzados de listas que cubrirá parte de lo que necesitas. Mientras tanto, puedes intentarlo a modo de ejercicio, te aseguro que si lo consigues aprenderás un montón 😉

  103. Ahora entra en onEntrada, pero no me encuentra el de id.titulo….

    TextView texto_superior_entrada = (TextView) view.findViewById(R.id.titulo);

    me dice que esto es null

    Sugerencias???

    1. Comprueba que no estén equivocados los id. O que hubieras variado algo del adaptador, pues si onEntrada no recibe vien los parámetros de la entrada, por ejemplo que devuelva view a null, pues será null. No te puedo decir mucho más sin ver el estado actual del código.

      De todas maneras, decirte que con las modificaciones que me indicaste, se asignó todo correctamente, funcionaba todo. Por lo que si no lo has modificado a como está hecho en el tutorial, debería de funcionarte.

  104. Resumo:

    tengo el archivo activity_menu_activity. xml del siguiente modo:

    <LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
    android:orientation=”vertical”
    android:layout_width=”fill_parent”
    android:layout_height=”fill_parent”>

    <TextView android:id=”@+id/titulo_chat”
    android:layout_width=”fill_parent”
    android:layout_height=”wrap_content”
    android:text=””
    android:layout_margin=”10px”
    android:gravity=”center”
    android:textSize=”10pt”/>
    <FrameLayout android:layout_width=”fill_parent”
    android:layout_height=”0dip”
    android:layout_weight=”9″>
    <ListView android:id=”@android:id/list”
    android:layout_width=”fill_parent”
    android:layout_height=”fill_parent”
    android:drawSelectorOnTop=”false” />
    <TextView android:id=”@android:id/empty”
    android:layout_width=”fill_parent”
    android:layout_height=”fill_parent”
    android:text=”@string/No_msg” />
    </FrameLayout>
    </LinearLayout>

    luego tengo los elementos que van dentro de este layout element_list.xml

    <?xml version=”1.0″ encoding=”utf-8″?>
    <RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android”
    android:layout_width=”fill_parent”
    android:layout_height=”?android:attr/listPreferredItemHeight”>
    <TextView android:id=”@+id/titulo”
    android:layout_width=”wrap_content”
    android:layout_height=”wrap_content”
    android:layout_alignParentTop=”true” />
    <TextView android:id=”@+id/subtitulo”
    android:layout_width=”wrap_content”
    android:layout_height=”wrap_content”
    android:layout_alignParentBottom=”true” />
    </RelativeLayout>

    y tras crear la clase lista_Adaptador y lista_Entrada tal y como tu las tienes, quitando el lista_Entrada lo correspondiente a la imagen, llamo a la vista y el adaptador del siguiente modo:

    setContentView(R.layout.activity_menu_activity);

    lista = (ListView) findViewById(R.id.titulo);
    lista.setAdapter(new Lista_adaptador(this, R.layout.activity_menu_activity, amigos){
    @Override
    public void onEntrada(Object entrada, View view) {
    TextView texto_superior_entrada = (TextView) view.findViewById(R.id.titulo);
    texto_superior_entrada.setText(((Lista_entrada) entrada).get_textoEncima());

    TextView texto_inferior_entrada = (TextView) view.findViewById(R.id.subtitulo);
    texto_inferior_entrada.setText(((Lista_entrada) entrada).get_textoDebajo());

    }
    });

    y el problema que me da es que lista es null

    lista esta creada como variable global.

    Que ocurre??Como puedo solucionarlo??

    1. Cambiando cosas he conseguido que vea el listView y que ya no sea null pero, no me carga nada, he puesto un breakpoint dentro del onEntrada, y no entra y estoy segura de que el array tiene datos, alguna sugerencia??

      1. El error está en la línea de la declaración de la lista. Ésta es la que está mal:
        lista = (ListView) findViewById(R.id.titulo);

        Prueba con:
        ListView lista = (ListView) findViewById(R.id.list);

        Fíjate que has puesto de id titulo, con lo que te testaba seleccionando otra cosa que no era un ListView.

        Corrigiendo esto se corregirán todos los errores, pues en el onEntrada no entrará si no está asignado a un ListView.

        Prueba corrigiendo esto y me cuentas a ver que tal 🙂

        1. eso no funciona, porque como no es un id asignado con + sino que es un tipo que tiene por defecto android, cuando pongo el list, no funciona, ya lo he probado.

          Y lo de que no entraba en el onEntrada, lo digo despues de haber cambiado cosas

          actualmente mi element_list.xml es tu primer archivo xml (quitando lo de la imagen, pero tal cual)
          y mi activity_menu_actividad.xml es como tu listado.xml

          e puesto todo tal y como lo pones tu

          me encuentra listView y lo asigna, ya no me da null, pero ahora, no entra en onEntrada, y por lo tanto no me pinta nada, da error en la apliación, pero no soy capaz de ver cual es en el debugger. y lo dicho, el array tiene elementos dentro

          1. Tienes toda la razón, no me había fijado en que utilizas el id de los recursos de Android 🙁

            Pon para acceder al id del recurso de Android remplaza la línea antes comentada por:
            lista = (ListView) findViewById(android.R.id.list);

            Con esto te funcionará a la perfección, también el onEntrada.

            Una aclaración, al usar los recursos de Android estás aceptando usar sus adaptadores creados para ellos. El TextView de id “@android:id/empty” no aparecerá al usar el adaptador de aquí porque el adaptador no lo soporta. Los de Android sí, como el listItemAdapter, pero no te permiten personalizar tanto las filas.

  105. Hola estoy seguiendo tu tutorial, pero me da una nullPointer exception cuando ejecuta esta linea:

    lista.setAdapter(new Lista_adaptador(this, R.layout.element_list, amigos){

    alguna idea

    he comprado que en amigos tengo 5 elementos y R.layout.elemen_ list es:

    alguna idea o sugerencia de porque puede ser??

      1. si creo que el problema esta ahi porque al ejecutar

        lista = (ListView) findViewById(R.id.elemento);

        me dice que el elemento lista es null

        mi layout es:

        <?xml version=”1.0″ encoding=”utf-8″?>
        <RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android”
        android:id=”@+id/elemento”
        android:layout_width=”fill_parent”
        android:layout_height=”?android:attr/listPreferredItemHeight”>

        <TextView android:id=”@+id/titulo”
        android:background=”@drawable/gradient_box”
        android:layout_width=”wrap_content”
        android:layout_height=”wrap_content”
        android:layout_alignParentTop=”true” />

        <TextView android:id=”@+id/subtitulo”
        android:background=”@drawable/gradient_box2″
        android:layout_alignParentRight=”true”
        android:layout_width=”wrap_content”
        android:layout_height=”wrap_content” />
        </RelativeLayout>

        algun consejo?

        1. Despues de ponerlo tal y como esta el tuyo, me da el error al hacer

          setContentView(R.layout.activity_menu_activity);

          donde activity_menu_activity, es igual a la lista de los elemento

          el error que me da es emptyView null

          1. ese elemento, es parte @android:id/list complementeria de un empty

            alguna idea porque sale null lista y como solucionarlo??

  106. una pregunta adicional cuando agregas al disegno un control de formulario (Button,edittext,checkbox,etc) el listener ya no funciona, porque ? solo cuando agregas un imageview o textview si funciona, todo esto en la parte xml, sin nada de codigo java ?

    saludos

  107. Hola Ramon, gracias por la sugerencia, voy a intentar lo q me dice y luego les comento, con respecto al xml tengo una duda si esta bien ubicado las etiiquetas del radiogroup ? :

    <selector xmlns:android=”http://schemas.android.com/apk/res/android”>
    <item android:state_checked=”false” android:drawable=”@drawable/icon_off” />
    <item android:state_checked=”true” android:drawable=”@drawable/icon_on” />
    </selector>

    luego para el xml de cada item:

    <TextView
    android:id=”@+id/tv01″
    android:layout_width=”fill_parent”
    android:layout_height=”wrap_content”
    android:text=”Info” />
    <ToggleButton
    android:layout_width=”wrap_content”
    android:layout_height=”wrap_content”
    android:background=”@drawable/toggle_style”
    android:textOff=””
    android:textOn=”” />

    luego tengo el xml que mostrara la lista :
    <RadioGroup
    android:id=”@+id/toggleGroup”
    android:layout_width=”wrap_content”
    android:layout_height=”wrap_content” >
    <ListView
    android:id=”@android:id/list”
    android:layout_width=”wrap_content”
    android:layout_height=”wrap_content”>
    </ListView>
    </RadioGroup>

    1. Buenas Alek,

      Parece que quieres hacer una lista por exclusión de RadioGroup. Pero el RadioGroup solo sirve para crear un conjunto de RadioButtons (ver en: http://developer.android.com/reference/android/widget/RadioGroup.html). Por lo que no te sirve para excluir dentro del ListView, al ser el hijo inmediatamente inferior el ListView 😉

      Otra cosa que puedes hacer, es guardar el cuerpo de la función onEntrada detectar el onClick del elemento que quieres pulsar, guardar su id como global en la actividad. Y cuando se pulse otro, ver cual id está guardado y despulsar el anterior. Prueba a ver si te gusta más así, que así no tocas el adaptador para nada, cosa que recomiendo no tocar el adaptador salvo casos de última necesidad 🙂

      1. Gracias Ramon por el consejo, fianlmente pude implementar una funcionalidad del tipo radiobutton con un toggle button… dentro del listener para cada item y luego pasar el id del view a otra funcion para que reinicie los view salvo el que se envia como parametro :

        lista.setOnItemClickListener(new OnItemClickListener() {
        @SuppressWarnings(“deprecation”)
        @Override
        public void onItemClick(AdapterView pariente, View view, int posicion, long id) {
        @SuppressWarnings(“unused”)
        ListEntity elegido = (ListEntity) pariente.getItemAtPosition(posicion);

        varToggle = (ToggleButton) view.findViewById(R.id.BtnToggle);
        varToggle.setChecked(true);

        //msg alerta/confirmacion
        showDialog(0);
        //showDialog(DIALOGO_SELECCION);

        //limpieza de btn’s
        reStart(posicion);
        }
        });

        public void reStart(int posicion){
        for(int j=0;j<lista.getCount();j++)
        {
        View vista = lista.getChildAt(j);
        ToggleButton varToggle2 = (ToggleButton) vista.findViewById(R.id.BtnToggle);
        if(j != posicion){ varToggle2.setChecked(false); }
        }
        }

        aprovecho la ocasion, para preguntar algo mas, tengo una actividad que muestra en pantalla varios botones, habra 2 usuarios que veran la misma activity en 2 telefonos en simultaneo, haciendo aparte el tema de transporte de la data entre los 2 terminales, necesito crear un flag para que cuando el primer usuario envie una invitacion sus botones se desactiven, mientras que el usuario que recibe la invitacion, recibira el flag para activar sus botones, solo una vez que el segundo haya presionado un boton cualquiera, enviara de vuelta el flag para que se activen sus flag, todo esto ocurrira solo una vez, tengo la logica del proceso, pero tengo dudas como implementarlo en android ? alguna sugerencia, deberia usar el metodo onStart() ?

        nuevamente gracias por los consejos, este articulo del listview lo estoy reutilizando en diferentes combinaciones, es realmente muy bueno para partir de base para otras cosas mas complejas.
        un saludo cordial

        1. Me alegro que te haya servido, con perseverancia todo termina funcionando 🙂

          No sé si te fijaste, abrimos un nuevo artículo con las preguntas más frecuentes. Simulo el radiogroup de otra manera dentro de un listado, por si te interesa: http://jarroba.com/expansion-listview/

          Sobre tu nueva consulta, lo que yo haría sería poner un hilo de escucha o un listener dependiendo de la necesidad (comentas usar el método onStart, te desaconsejaría su uso para esto, pues solo se lanza en determinados momentos y no estarías cazando el flag en el momento de la recepción). Yo recomiendo tener un listener (el típico setOnListener…, como el de los botones setOnClick) para no estar consumiendo procesador continuamente con un hilo de escucha en un while infinito, esto dependerá también un poco de como lo tengas programado y de la necesidad. Así, cuando el usuario presione el botón en el teléfono, este botón se bloqueará, pero quedara a la escucha de ser desbloquedado por un flag.

  108. Hola amigos, vuelvo otra vez sobre este tutorial, ahora quiero agregar un boton (togglebutton) a cada item de la lista, al inicio todos los botones deberan estar desactivados y cuando presione sobre uno de ellos se active y deshabilite los demas. Algo como los “RadioGroup” pero en lugar de radiobutton seria togglebutton.
    Para personalizar comence un “selector” ya que usare 2 imagenes para el togglebutton :

    luego para el xml de cada item :

    luego tengo el xml que mostrara la lista :

    el togglebutton funciona bien, pero no logro que al presionar uno se deshabilite los otros, me gustaria tambien detectar el boton activado para llamar alguna accion, talvez enviar un toast cuando se presiona a manera de ejemplo.

    tendrian alguna sugerencia de como lograrlo, gracias de antemano.

    1. Buenas alek,

      El código XML no aparece debido al sistema de comentarios de wordpress, que no admiten tags xml. Puedes usar esta página para escapar los símbolos mayor que y menor que y luego pegar aquí el código: http://www.htmlescape.net/htmlescape_tool.html

      Lamentamos estos inconvenientes 🙁

      Respecto a tu consulta, lo que haría sería poner una variable de posicionPulsada en el adaptador y que guardara la posición en el arrayList; para cuando se pulse otro, se elimine la selección del ya pulsado, guardado en esta variable posicionPulsada la nueva selección. Intenta a ver que tal y nos cuentas 😀

  109. Hola!
    La verdad que el tutorial es realmente bueno, me ha ayudado mucho en el tema 😉

    Pero ahora estoy intentando borrar elementos de la lista haciendo:
    datos.remove()

    y aunque se borran, no consigo actualizar la lista en el momento…

    Buscando en internet todo el mundo usa notifyDataSetChanged() sobre su adaptador en una lista básica, pero no sé cómo aplicarlo a una lista personalizada como la que hemos hecho.

    Muchas gracias de antemano por la ayuda, y enhorabuena de nuevo por el tutorial!

    1. Hola Alex,

      Estás en lo correcto. Cuando eliminas un elemento del arrayList, se elimina de ahí y nada más. Para refrescar el listado que se ve en pantalla se ha de llamar a notifyDataSetChanged(); que es un método del adaptador.

      El ejemplo de este artículo funciona muy bien para añadir elementos, se diseñó así para que fuera sencillo de entender, con el menos código posible, además de lo más global y útil.

      Para hacer cosas complejas hay que cambiar el adaptador, y el borrado es una de ellas, pues necesita el adaptador ser notificado de los cambios.

      No sé como andarás de Java y de clases abstractas, interfaces, etc. Te cuento para que lo intentes (si no lo consigues, tranquilo, estoy diseñando una segunda parte de este tutorial con listas complejas en las que explicaré esto). Al usar una clase abstracta no se permite la instancia, con lo que hay que modificar el adaptador a una clase normal. Luego hay que pedir el onEntrada por una interfaz. Así ya podremos instanciar el adaptador y poder llamar a métodos tales como refrescarLista() en el momento que lo necesitemos, que contendrá una llamada a notifyDataSetChanged();

      Siento no ser más preciso, lo seré en cuanto tenga listo el siguiente artículo de listas. Aunque tampoco lo esperes pronto, este mes lo tengo a tope de cosas y no le puedo dedicar tanto como me gustaría. Aunque estar estará, te lo aseguro 🙂

      1. Hola!

        Lo primero darte las gracias por la rapidez en contestar y por el esfuerzo que estás dedicando 😉

        Voy a investigar un poco la solución que me dices con la interfaz.

        De todas formas, hasta que lo encuentre (o publiques tu nuevo artículo =P) he hecho una solución muy cutre de emergencia: simplemente después de borrar vuelvo a lanzar la actividad en la que tengo mi lista, y consigo que así se refresque.
        Sé que es muy cutre y posiblemente tenga algún inconveniente que desconozca, pero para ir tirando de momento me sirve 😉

        Una vez más, gracias por tu tiempo!

        Alex.

        1. De nada Alex, estamos para ayudar en lo que esté de nuestra mano y de la mejor manera 😀

          Un consejo, evita lo más posible lanzar actividades (salvo que sean necesarias para mostrar las vistas, claro). Pues su creación consume bastantes recursos por la carga que suelen tener (tanto que se suele notar el parpadeo de la inicialización en la mayoría de dispositivos). Además, si hay muchas actividades en la pila de actividades, puede que el botón de atrás del terminal sea tedioso de usar. O incluso Android termine actividades no deseadas de ser finalizadas.

  110. Amigo, muy bueno, el ejemplo, disculpa la pregunta, lo que pasa esque yo quiero saber si se puede hacer lo mismo pero tomando la información textual desde un archivo exm com recurso, o sea Bhuo, colibri y cuervo en un nomb_animales.xml y descr_animales.xml ?? o si se puede de pronto desde archivos de texto plano o cual de los 2 es más optimo de manejar.???? de antemano gracias por tu tiempo.

    1. En mi caso, tambien hice pruebas para obtener la informacion a partir de un archivo, puedes agregar estas lineas justo antes del try de la funcion, el resto quedaria igual :

      Resources res = activity.getResources();
      XmlResourceParser xpp = res.getXml(R.xml.test);

      el archivo esta dentro de una carpeta llamada xml que a su vez esta en la carpeta res.

      espero te sirva de algo, por lo demas no se cual es mas optimo, recien empiezo con android y todavia tengo problemas para hacer funcionar el codigo que va dentro del onCreate, pero la funcion de parseo xml funciona muy bien.

      saludos

    2. Buenas Willian,

      Como bien te ha indicado Alek, puedes acceder a través de getResouces y parsearlos getXml, y que puedes recorrer con next(). Es muy buena solución para los casos en los que Android no reconoce la estructura del archivo, o quieres recorrerlo a mano. Te ofrezco otra alternativa, que para lo que necesitas, conjuntos de Strings ordenados, es más simple 🙂

      Empezar por aclarar tu pregunta final. Los textos en plano para archivos que son finales (finales me refiero a que no van a variar dinámicamente con Java, los xml son todos finales) mejor no usarlos (requieren permisos innecesarios, son más complicados de leer, hay que tratar la apertura y cerrado del archivo, tienes que manejar el puntero, etc). Mejor usa xml como te explico a continuación, que Android lo ha optimizado para ello.

      Para hacer lo que necesitas tienes que ir al directorio “res” y crear una carpeta llamada “values” si no existe ya. Aquí crea los xml con los datos que necesites, en formato String Array (en tu caso nomb_animales.xml y descr_animales.xml). Dentro de cada xml tienes que definir una estructura de XML como por ejemplo la siguiente lista de planetas (Ejemplos extraídos de: http://developer.android.com/guide/topics/resources/string-resource.html#StringArray):

      <?xml version="1.0" encoding="utf-8"?>
      <resources>
      <string-array name="planets_array">
      <item>Mercury</item>
      <item>Venus</item>
      <item>Earth</item>
      <item>Mars</item>
      </string-array>
      </resources>

      En tu caso en vez de ser planetas, define los textos que necesites. Cabe indicar que puedes crear varios arrays en un mismo archivo, no hace falta que estén separados (mientras estén encerrados y con nombre diferente entre las etiquetas <string-array name="nombre_de_mi_array">...</string-array>), al menos que lo necesites. Un solo archivo es más óptimo que varios.
      Para llamar a cada array xml desde Java y almacenarlos en un array de Java:

      Resources res = getResources();
      String[] planets = res.getStringArray(R.array.planets_array);

      Así ya podrás recorrer el array y guardar cada conjunto de datos en un objeto Lista_entrada.

      Y no hay nada que disculpar, es una buena pregunta y puedes preguntar lo que necesites. Si te podemos ayudar mejor que mejor 😉

  111. Gracias Ramon por responder, tengo la idea general pero hace dias que me esta costando hacer la adaptacion. Mi entidad define 2 valores enteros. Dentro de mi “public class MainActivity” tengo la funcion getAllXML(me parsea un string xml para recuperar 2 valores).

    Y en la clase principal tengo esto :

    public class FuncionActivity extends ListActivity {

    private String xmlc = “52”;

    ///
    List datattt = null;
    private EntidadTest dataxml;

    public List getAllXML(){

    try {
    //String source
    XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
    factory.setNamespaceAware(true);
    XmlPullParser xpp = factory.newPullParser();
    xpp.setInput(new StringReader(xmlc));

    xpp.next();

    while (xpp.getEventType()!=XmlPullParser.END_DOCUMENT) {
    dataxml = new EntidadTest(0, 0);
    if (xpp.getEventType()==XmlPullParser.START_TAG) {
    if (xpp.getName().equals(“cel”)) {
    dataxml.setPropiedad( Integer.parseInt(xpp.nextText()) );
    }
    if (xpp.getName().equals(“val”)) {;
    dataxml.setValor( Integer.parseInt(xpp.nextText()) );
    }
    }
    xpp.next();
    }

    } catch (XmlPullParserException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    return datattt;
    }

    y al final cuando se quiere mostrar los valores en una lista (Listview) pienso que es mas facil ya que seria cuestion de hacer un bucle e ir pintando los valores, pero como haces si quieres asignar los valores en forma directa, x ejm en la interfase tengo 5 controles, y yo quiero mostrar el valor 1 que recupero en el et02(edittext) y el valor 2 en el et05(edittext) ? es decir como asignas un valor de una posicion especifica de la lista_adaptador a un determinado control ? … llevo semanas y aun no logro descifrarlo todo. Gracias de antemano nuevamente.

    1. No te preocupes, pasa al principio, ya verás como una vez que lo entiendas es muy sencillo.
      Vamos a desgranar la idea que tienes y como ir paso a paso:
      1) Recogemos los datos de Internet.
      2) Cada conjunto de datos (entiendo que serán una propiedad y un valor), los añado a una entidad, que en el ejemplo los hemos llamado “Lista_entrada” (tu la has llamado “EntidadTest”)
      3) Cada entidad recogida la añadimos a la lista (esta lista me refiero al arrayList), que en el ejemplo llamo “datos”, que es una arrayList de tipo genérico “Lista_entrada” (lo que es lo mismo a decir, tengo una lista que se llama “datos” y que solo va a contener en cada campo de la lista un tipo “Lista_entrada”).

      Con estos pasos ya lo tenemos sencillo, solo tenemos que ver donde colocar cada cosa, y decirte que no ibas tan mal:

      public class FuncionActivity extends ListActivity {

      private String xmlc = “52″;

      public ArrayList<EntidadTest> getAllXML(){

      ArrayList<EntidadTest> datos = new ArrayList<Lista_entrada>(); //Creamos nuestro arrayList a devolver

      try {
      //String source
      XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
      factory.setNamespaceAware(true);
      XmlPullParser xpp = factory.newPullParser();
      xpp.setInput(new StringReader(xmlc));

      xpp.next();

      while (xpp.getEventType()!=XmlPullParser.END_DOCUMENT) {
      dataxml = new EntidadTest(0, 0);
      if (xpp.getEventType()==XmlPullParser.START_TAG) {
      int propiedad = 0;
      int valor = 0;

      if (xpp.getName().equals(“cel”)) {
      propiedad = Integer.parseInt(xpp.nextText()); //Recogemos la propiedad
      }
      if (xpp.getName().equals(“val”)) {;
      valor = Integer.parseInt(xpp.nextText()); //Recogemos el valor
      }

      EntidadTest miEntidad = new EntidadTest(propiedad, valor); //Creamos la entidad con la propiedad y el valor
      datos.add(miEntidad); //Añadimos la entidad a la lista
      //Estos dos últimos pasos, personalmente me gusta resumirlos en: datos.add(new EntidadTest(propiedad, valor));

      }
      xpp.next();
      }

      } catch (XmlPullParserException e) {
      e.printStackTrace();
      } catch (IOException e) {
      e.printStackTrace();
      }
      return datos;
      }

      Esta función nos devuelve nuestro ArrayList listo para ser colocado en el adaptador:

      ArrayList<EntidadTest> datosParaAdaptador = getAllXML();

      ListView lista = (ListView) findViewById(R.id.ListView_listado);
      lista.setAdapter(new Lista_adaptador(this, R.layout.entrada, datosParaAdaptador){
      @Override
      public void onEntrada(Object entrada, View view) {
      //TODO poner código de asignación a la vista (ver ejemplo del artículo)
      }
      });

      Con esto ya lo tendrías 🙂

      1. Gracias Ramon, finalmente logre hacer funcionar mi ejemplo, revise todo con atencion y pude completar mi ejemplo. Aprovecho la ocasion para peguntarte si tienes/conoces un articulo o tutorial que muestre como enviar datos entre 2 dispositivos mediante TCP/IP ?

        Saludos cordiales

        1. Hola Alek.
          Por la experiencia que tenemos y salvo que mi compañero Ramon me diga lo contrario, para enviar datos de un dispositivo a otro (por TCP/IP) necesitas entre medias un servidor para guardar el dato que quieras enviar y mediante “Push” con el otro dispositivo recibas el dato (si es que lo quieres que lo reciba inmediatamente, sino seria por “pull”).

          Para hacerlo de forma mas inmediata sin TCP/IP seri hacerlo utilizando el Bluetooth. Eso por ahora sabemos que es posible hacerlo pero hasta la fecha no hemos hecho nada con eso.

          Si nos enteramos de algo ya te lo diremos o sino que me corrija mi compañero Ramon 😉

          SL2

          1. Gracias por responder y felicitaciones por los tutoriales, me esta ayudando mucho a ingresar al mundo de android. Por lo de la comuncicacion entre 2 dispositivos por lo que he leido parace que no es necesario tener un servidor fisico sino una aplicacion que actue como servidor y cliente a la vez, al parecer esto se puede hacer con sockets, en muchos sitios de internet hacen referencia a los principios de este articulo : http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/
            pero es solo el principio basico, parece que hay problemas si los dispositivos moviles estan en la misma red y hasta ahora no he encontrado un ejemplo concreto que muestre el funcionamiento de una aplicacion bidireccional, solo encuentro ejemplos de una direccion y roles fijos (cliente – servidor).
            Gracias nuevamente y estare al pendiente de los nuevos articulos que publiquen. Exitos en su aventura digital!

        2. Buenas alek,

          como bien te ha comentado Richard: lo más recomendable es desde un dispositivo, que comunique a un servidor lo que sea, y con una conexión al GCM de Google enviar un push al otro dispositivo.

          Con sockets no deberías de tener problemas de conectar dos dispositivos haciendo uno de cliente y otro de servidor. Por razones de tiempo, no vamos a poder realizar un tutorial de sockets de momento.

          Mientras tanto, te recomiendo que sigas este tutorial gratuito de Android: http://www.androidcurso.com/index.php/recursos-didacticos/tutoriales-android , tienes un ejemplo de sockets en el tema 10, aunque te recomiendo que te lo mires entero, es muy bueno.

          Gracias por los ánimos, esperamos que te sea grata la experiencia Androide 🙂

          1. Alek, muchas gracias por la aportación, no sabia que se podia hacer de esa forma, teniendo un movil “como servidor”.

            Por ahora las aplicaciones que tenemos hechas las hacemos utilizando un servidor entre medias. Por si te interesa puedes hechar un ojo a nuestras apps: https://play.google.com/store/apps/developer?id=Vallekano85

            Tendremos en cuesta lo que nos has contado e intentaremos en un futuro hacer algo relacionado con eso porque nos parece muy interesante, aunque Ramón y yo llevamos unos meses muy liados 😉

            Bueno muchas gracias por tu aportación y gracias por seguirnos.

            SL2

  112. Buenas, gracias por el articulo, empiezo a entender mejor el tema de los adapter en android, si he entendido bien, se necesita una clase entidad, luego se crea el adaptador extendiendo la clase baseadapter, se instancia el arraylist y se llama al adapter en la clase principal, esto resumiendo el proceso del ejemplo. Pero tengo una duda, en el caso de que en una clase principal (un activity) tenga una funcion ( HacerAlgo() ) que me devuelve valores, como o donde las declaraciones para almacenar esos valores en mi adapter ? no logro entender del todo como puedo agregar un adapter dentro de una funcion ? Gracias de antemano

    1. Buenas alek,

      vas por muy buen camino, es así como funciona un adaptador 🙂

      Sobre tu pregunta, tienes una función que te devuelve los valores para almacenar en la lista. Depende un poco de como tengas el código de esa función, se me ocurren dos casos:

      1) Si puedes modificar la función HacerAlgo. Lo más rápido es que devuelva directamente el ArrayList con los datos ya preparados para pasar al adaptador. Por ejemplo:

      public ArrayList< Lista_entrada> HacerAlgo(){
      ArrayList< Lista_entrada> datos_a_devolver = new ArrayList();

      // ... INICIO DE BUCLE
      int R_drawable_img = 0;
      String nombre = "";
      String descirpcion = "";

      // ... Asignación de los datos a las variables anteriormente declaradas

      datos_a_devolver.add( new Lista_entrada(R_drawable_img , nombre , descirpcion) );

      //... FIN DE BUCLE
      }

      Luego, siguiendo el ejemplo, modificaríamos en el onCreate:
      lista.setAdapter(new Lista_adaptador(this, R.layout.entrada, HacerAlgo() ){ ... });

      2) En caso de que no puedas modificar la función HacerAlgo(), podrías hacer algo parecido, pero creando en un bucle el ArrayList con el resultado de los valores devueltos por la función.

  113. Perdón he enviado el anterior comentario sin terminar.

    …”Please try again. Force close”

    No se que puede estar pasando.
    Alguna pista?

    Que comprobaciones puedo hacer?.

    Gracias!!!

    1. Buenas,

      Lo que nos comentas, es el mensaje de error en tiempo de ejecución. Mensaje que sale a modo de ventana emergente, en el propio sistema operativo de Android, al ejecutar una aplicación.

      Este error se debe a un sin fin de causas, y sin más datos que describan el problema no podemos ayudarte más 🙁

      Si nos has mandado algo en otro comentario no lo hemos recibido. Si puedes volver a subirlo te lo responderemos con gusto.

  114. Hola!!

    Enhorabuena por el tutorial.

    Soy nuevo en Android, he importado el proyecto entero, y no detecta ningun error, pero al lanzar la aplicacion e intentar hacer un scroll de la lista, salta un error: “The application Listado (process jarroba.ramon.listado) has stopped unexpectedly

  115. Excelente
    Tutorial!
    Podrían compartir el código cargando los datos en el listview mediante el webservice en Json. Seria de mucha utilidad, se los agradezco.

  116. Gracias por contestar Richard.
    Al final lo solucione pasandole “Nombre_actividad.this” y funciono perfectamente.

    Una pregunta.
    No seria mas cómodo crear en la clase Lista_adaptador un viewHolder con todos los elementos que se van a visualizar, en vez de tener que ponerlos al establecer el adaptador con la función “onEntrada”??

    De esta forma no seria mas fácil eliminar objetos del adaptador? y a su vez de la lista? Corrígeme si me equivoco. 🙂

    Saludos!

    1. Buenas Erik,
      Sí, se puede hacer perfectamente con un viewHolder para manejar las Views que aparecerán en el listado, con lo que se puede personalizar el adaptador para que la lista realice otras funciones más avanzadas.
      Lo que aquí pretendemos al usar el método abstracto “onEntrada” es simplificar y evitar tener que tocar el código del adaptador, olvidarnos de él, ya que tampoco aporta mucho para la mayoría de los listados con elementos personalizados que se suelen hacer (lo que es hacer un copia y pega y cambiar dos cosas para que funcione).
      Puede que aquí se confunda el termino dinámico, de ahí tu duda. Me refiero a dinámico a que no toma de un array normal y hace un listado de elementos simples de texto, sino que podemos tomar los datos de internet, por ejemplo, y crearlo con multitud de elementos como imágenes, textos, checkbox, en definitiva, todo lo que queramos. De todas maneras voy a cambiar un poco el tutorial para que no quepan dudas.
      Ya si queremos otra clase de listados más dinámicos todavía, son más avanzados y la cosa cambia. Como que tengan animaciones de entrada cada elemento, eliminar elementos, que se añadan elementos a medida que se desciende en el listado, etc. Estamos trabajando en un tutorial para estos casos más avanzados 😉

  117. Buenos días!

    Estoy usando vuestro código para cargar un ListView con datos que obtengo de un webService mediante Json.

    Tengo un AsynTask en la cual en la función doInBackground() añado los datos obtenidos mediante JSON al Array datos, es decir :
    datos.add(new list_entrada(id, nombre, apellido, personas, tachado));

    y en la función onPostExecute() quiero añadir el código para usar el adaptador y aquí es donde viene el problema:
    – Me hace cambiar el parámetro de la clase Lista_adaptador “Context contexto” por “Runnable runnable”.
    – Cambio los parámetros pero no me muestra nada, no se carga el listview.

    A ver si podéis ayudarme, que llevo ya 3 días dándole vueltas y me estoy volviendo loco!! 🙁

    Por cierto, gracias por el código y fantástico tutorial, muy bien explicado!

    Saludos!

    1. ¡Ojo!, que el hilo que extiende de AsynTask se ejecuta en otra clase diferente, que a su vez hereda de Runnable, NO de Activity. Por lo que si dentro de una clase que hereda de AsynTask, al llamar al “this” NO llamas al contexto de la aplicación, sino al objeto de tipo Runnable.
      Para obtener el contexto dentro del Asyntask puedes puedes hacer una de estas dos cosas (te recomiendo la primera):

      A) Llamar directamente al método getActivity() que devuelve el contexto. Por ejemplo:
      Context contexto = getActivity();

      B) Pasar el contexto a la clase que extiende de AsynTask. De la actividad que crea la clase Asyntask, pasarle directamente el contexto en el contructor o en el execute (si quieres pasar el contexto directamente al doInBackground). Por ejemplo, para pasarlo en el execute:
      new miAsynTask().execute(contexto);
      y dentro de la clase que hereda de AsynTask, en el método doInBackground:
      protected Integer doInBackground(Context... contexto_pasado) {
      Context contexto = contexto_pasado[0];
      }

      1. Buenas, en primer lugar gracias por el ejemplo, es muy claro todo. Espero que me puedas ayudar con mi siguiente problema:

        Estoy intentando hacer lo mismo, pero los datos que quiero mostrar en el ListView los recojo de un Json que obtengo de una base de datos que tengo en mysql. He leído aquí algunos comentarios de gente que tiene el mismo problema que yo, pero no me queda muy clara la solución, a ver si puedes ayudarme a solucionarlo, te dejo escrito el código a ver si puedes ver donde está el fallo:

        package com.example.mysqltest;

        import java.io.BufferedReader;
        import java.io.IOException;
        import java.io.InputStream;
        import java.io.InputStreamReader;
        import java.util.ArrayList;
        import org.apache.http.HttpEntity;
        import org.apache.http.HttpResponse;
        import org.apache.http.client.ClientProtocolException;
        import org.apache.http.client.HttpClient;
        import org.apache.http.client.methods.HttpGet;
        import org.apache.http.impl.client.DefaultHttpClient;
        import org.json.JSONArray;
        import org.json.JSONException;
        import org.json.JSONObject;
        import beans.Client;
        import android.app.Activity;
        import android.content.Context;
        import android.os.AsyncTask;
        import android.os.Bundle;
        //import android.widget.ArrayAdapter;
        import android.widget.ListView;

        public class ViewClientClass extends Activity{

        //static ViewClientClass activity;
        Context context = getApplicationContext();
        ListView lv_clients;

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

        lv_clients = (ListView)findViewById(R.id.lv_clients);

        Task1 task1 = new Task1();
        task1.loadContent(getApplicationContext());
        task1.execute(lv_clients);
        }

        static class Task1 extends AsyncTask {

        Context context;
        ListView list;
        InputStream is;
        ArrayList clientList = new ArrayList();

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

        @Override
        protected void onPreExecute(){

        }

        @Override
        protected ItemAdapter doInBackground(ListView… params) {
        list = params[0];
        String result = “Error”;
        Client cli;

        HttpClient client = new DefaultHttpClient();
        HttpGet get = new HttpGet(“http://10.0.2.2/Android/ver.php”);
        try{
        HttpResponse response = client.execute(get);
        HttpEntity content = response.getEntity();
        is = content.getContent();
        }
        catch(ClientProtocolException e){
        e.printStackTrace();
        }
        catch(IOException e){
        e.printStackTrace();
        }

        BufferedReader buferreader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = null;
        try{
        while((line = buferreader.readLine())!=null){
        sb.append(line);
        }
        }
        catch(IOException e){
        e.printStackTrace();
        }
        try{
        is.close();
        }
        catch(IOException e){
        e.printStackTrace();
        }
        result = sb.toString();

        try{
        JSONArray arrayJson = new JSONArray(result);
        for(int i = 0; i < arrayJson.length(); i++){
        JSONObject objectJson = arrayJson.getJSONObject(i);
        cli = new Client(objectJson.getString("name"));
        clientList.add(cli);
        }
        }
        catch(JSONException e){
        e.printStackTrace();
        }
        //ArrayAdapter adapter = new ArrayAdapter(context,android.R.layout.simple_list_item_1,clientList);
        ItemAdapter adapter = new ItemAdapter(/*activity,*/clientList);
        return adapter;
        }

        @Override
        protected void onPostExecute(ItemAdapter result){
        list.setAdapter(result);
        }

        @Override
        protected void onProgressUpdate(Void… values){

        }

        }
        }

        /////////////////////////////////////////////////////////////

        Y este es mi adapter personalizado:

        package com.example.mysqltest;

        import java.util.ArrayList;
        import beans.Client;
        /*import android.app.Activity;
        import android.content.Context;
        import android.view.LayoutInflater;*/
        import android.view.View;
        import android.view.ViewGroup;
        import android.widget.BaseAdapter;
        import android.widget.TextView;

        public class ItemAdapter extends BaseAdapter{

        //protected Activity activity;
        protected ArrayList item;

        public ItemAdapter(/*Activity activity,*/ArrayList item){
        //this.activity = activity;
        this.item = item;
        }

        @Override
        public int getCount() {
        return item.size();
        }

        @Override
        public Object getItem(int position) {
        return item.get(position);
        }

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

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

        /*
        if(convertView == null){
        LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        vi = inflater.inflate(R.layout.list_view_item, null);
        }
        */

        Client myClient = item.get(position);

        TextView name = (TextView)vi.findViewById(R.id.tv_name_view);
        name.setText(myClient.getName());

        return vi;
        }

        }

        1. Buenas Daniel,

          el código lo único que me huele raro es que le estás pasando el ListView al DoInBackground(), quien no debe nunca tratar con las vistas (Echa un vistazo a: http://jarroba.com/asynctask-en-android/). Si fuera otro el error tendría que ver la traza, a ver si me la puedes copiar.

          Para Json en Android tienes un ejemplo bastante bien explicado en la documentación oficial, en http://developer.android.com/reference/android/util/JsonReader.html

          1. La cosa es que haciendolo con un adapter normal no da problema, y le paso también el ListView como parametro. Este sería el código con un adapter normal:

            package com.example.mysqltest;

            import java.io.BufferedReader;
            import java.io.IOException;
            import java.io.InputStream;
            import java.io.InputStreamReader;
            import java.util.ArrayList;
            import org.apache.http.HttpEntity;
            import org.apache.http.HttpResponse;
            import org.apache.http.client.ClientProtocolException;
            import org.apache.http.client.HttpClient;
            import org.apache.http.client.methods.HttpGet;
            import org.apache.http.impl.client.DefaultHttpClient;
            import org.json.JSONArray;
            import org.json.JSONException;
            import org.json.JSONObject;
            import beans.Client;
            import android.app.Activity;
            import android.content.Context;
            import android.os.AsyncTask;
            import android.os.Bundle;
            import android.widget.ArrayAdapter;
            import android.widget.ListView;

            public class ViewClientClass extends Activity{

            //static ViewClientClass activity;
            ListView lv_clients;

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

            lv_clients = (ListView)findViewById(R.id.lv_clients);

            Task1 task1 = new Task1();
            task1.loadContent(getApplicationContext());
            task1.execute(lv_clients);
            }

            static class Task1 extends AsyncTask <ListView, Void, ArrayAdapter>{

            Context context;
            ListView list;
            InputStream is;
            ArrayList clientList = new ArrayList();

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

            @Override
            protected void onPreExecute(){

            }

            @Override
            protected ArrayAdapter doInBackground(ListView… params) {
            list = params[0];
            String result = “Error”;
            Client cli;

            HttpClient client = new DefaultHttpClient();
            HttpGet get = new HttpGet(“http://10.0.2.2/Android/ver.php”);
            try{
            HttpResponse response = client.execute(get);
            HttpEntity content = response.getEntity();
            is = content.getContent();
            }
            catch(ClientProtocolException e){
            e.printStackTrace();
            }
            catch(IOException e){
            e.printStackTrace();
            }

            BufferedReader buferreader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line = null;
            try{
            while((line = buferreader.readLine())!=null){
            sb.append(line);
            }
            }
            catch(IOException e){
            e.printStackTrace();
            }
            try{
            is.close();
            }
            catch(IOException e){
            e.printStackTrace();
            }
            result = sb.toString();

            try{
            JSONArray arrayJson = new JSONArray(result);
            for(int i = 0; i < arrayJson.length(); i++){
            JSONObject objectJson = arrayJson.getJSONObject(i);
            cli = new Client(objectJson.getString("name"));
            clientList.add(cli);
            }
            }
            catch(JSONException e){
            e.printStackTrace();
            }
            ArrayAdapter adapter = new ArrayAdapter(context,android.R.layout.simple_list_item_1,clientList);
            //ItemAdapter adapter = new ItemAdapter(/*activity,*/clientList);
            return adapter;
            }

            @Override
            protected void onPostExecute(ArrayAdapter result){
            list.setAdapter(result);
            }

            @Override
            protected void onProgressUpdate(Void… values){

            }

            }
            }

          2. El código lo veo bien. Si te falla con el Adapter personalizado sólo, probablemente esté dando problemas cuando creas las Views desde el Adapter (en alguna se estará pasando un null).

            No te puedo decir mucho más sin un log con el error!!! 😀

          3. Todo esto es lo que me sale cuando falla la aplicación:

            04-11 04:02:16.374: W/System.err(805): org.apache.http.conn.HttpHostConnectException: Connection to http://10.0.2.2 refused
            04-11 04:02:16.385: W/System.err(805): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:183)
            04-11 04:02:16.424: W/System.err(805): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
            04-11 04:02:16.424: W/System.err(805): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
            04-11 04:02:16.434: W/System.err(805): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
            04-11 04:02:16.454: W/System.err(805): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
            04-11 04:02:16.454: W/System.err(805): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
            04-11 04:02:16.464: W/System.err(805): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
            04-11 04:02:16.464: W/System.err(805): at com.example.mysqltest.ViewClientClass$Task1.doInBackground(ViewClientClass.java:66)
            04-11 04:02:16.464: W/System.err(805): at com.example.mysqltest.ViewClientClass$Task1.doInBackground(ViewClientClass.java:1)
            04-11 04:02:16.464: W/System.err(805): at android.os.AsyncTask$2.call(AsyncTask.java:287)
            04-11 04:02:16.484: W/System.err(805): at java.util.concurrent.FutureTask.run(FutureTask.java:234)
            04-11 04:02:16.494: W/System.err(805): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
            04-11 04:02:16.494: W/System.err(805): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
            04-11 04:02:16.524: W/System.err(805): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
            04-11 04:02:16.524: W/System.err(805): at java.lang.Thread.run(Thread.java:841)
            04-11 04:02:16.534: W/System.err(805): Caused by: java.net.ConnectException: failed to connect to /10.0.2.2 (port 80): connect failed: ECONNREFUSED (Connection refused)
            04-11 04:02:16.584: W/System.err(805): at libcore.io.IoBridge.connect(IoBridge.java:114)
            04-11 04:02:16.594: W/System.err(805): at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
            04-11 04:02:16.614: W/System.err(805): at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)
            04-11 04:02:16.614: W/System.err(805): at java.net.Socket.connect(Socket.java:842)
            04-11 04:02:16.614: W/System.err(805): at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:119)
            04-11 04:02:16.674: W/System.err(805): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:144)
            04-11 04:02:16.674: W/System.err(805): … 14 more
            04-11 04:02:16.694: W/System.err(805): Caused by: libcore.io.ErrnoException: connect failed: ECONNREFUSED (Connection refused)
            04-11 04:02:16.714: W/System.err(805): at libcore.io.Posix.connect(Native Method)
            04-11 04:02:16.734: W/System.err(805): at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:85)
            04-11 04:02:16.734: W/System.err(805): at libcore.io.IoBridge.connectErrno(IoBridge.java:127)
            04-11 04:02:16.754: W/System.err(805): at libcore.io.IoBridge.connect(IoBridge.java:112)
            04-11 04:02:16.764: W/System.err(805): … 19 more
            04-11 04:02:16.764: W/dalvikvm(805): threadid=11: thread exiting with uncaught exception (group=0x41465700)
            04-11 04:02:16.824: E/AndroidRuntime(805): FATAL EXCEPTION: AsyncTask #1
            04-11 04:02:16.824: E/AndroidRuntime(805): java.lang.RuntimeException: An error occured while executing doInBackground()
            04-11 04:02:16.824: E/AndroidRuntime(805): at android.os.AsyncTask$3.done(AsyncTask.java:299)
            04-11 04:02:16.824: E/AndroidRuntime(805): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
            04-11 04:02:16.824: E/AndroidRuntime(805): at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
            04-11 04:02:16.824: E/AndroidRuntime(805): at java.util.concurrent.FutureTask.run(FutureTask.java:239)
            04-11 04:02:16.824: E/AndroidRuntime(805): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
            04-11 04:02:16.824: E/AndroidRuntime(805): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
            04-11 04:02:16.824: E/AndroidRuntime(805): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
            04-11 04:02:16.824: E/AndroidRuntime(805): at java.lang.Thread.run(Thread.java:841)
            04-11 04:02:16.824: E/AndroidRuntime(805): Caused by: java.lang.NullPointerException: lock == null
            04-11 04:02:16.824: E/AndroidRuntime(805): at java.io.Reader.(Reader.java:64)
            04-11 04:02:16.824: E/AndroidRuntime(805): at java.io.InputStreamReader.(InputStreamReader.java:122)
            04-11 04:02:16.824: E/AndroidRuntime(805): at java.io.InputStreamReader.(InputStreamReader.java:59)
            04-11 04:02:16.824: E/AndroidRuntime(805): at com.example.mysqltest.ViewClientClass$Task1.doInBackground(ViewClientClass.java:77)
            04-11 04:02:16.824: E/AndroidRuntime(805): at com.example.mysqltest.ViewClientClass$Task1.doInBackground(ViewClientClass.java:1)
            04-11 04:02:16.824: E/AndroidRuntime(805): at android.os.AsyncTask$2.call(AsyncTask.java:287)
            04-11 04:02:16.824: E/AndroidRuntime(805): at java.util.concurrent.FutureTask.run(FutureTask.java:234)
            04-11 04:02:16.824: E/AndroidRuntime(805): … 4 more

          4. Ya he resuelto el problema, y funciona perfectamente, el problema era que a mi adapter le estaba mandando la activity, cuando le tenia que mandar el context. Muchas gracias por vuestra ayuda!!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies

ACEPTAR