Spinners en Android, tres formas de poblarlos.
por DiCrEn en jun.02, 2011
¿Hola? ¿Hay alguien? Soy yo, DiCrEn, me recordarán por antiguos posts… de hace 2 años aproximadamente (sin contar con los de GPodcast). Por aquel entonces yo era un alegre jovenzuelo que se creía Dios por programar el snake con C, pero todo eso ha cambiado, ese jovenzuelo ha madurado, ha estudiado y ahora… se cree Dios por tener un par de aplicaciones en el Android Market
Me he propuesto volver a tener un poquito de continuidad en el blog, cosa que, por supuesto, no conseguiré, pero bueno…
Y dicho esto vamos a lo que vamos, los spinners de Android. Vamos a dejarnos de gilipolleces y vamos al tema, imagino que tendrás instalado el SDK de android, el eclipse, etc, y que hayas hecho algo para el S.O. de google. Si no es así esto te va a interesar más bien poco.
¿Que son los spinners?
Los spinners en Android son los combobox de toda la vida. Spinner significa, según el traductor de google, hilandero. ¿Porque google ha decidido llamarlo así y no combobox como se ha hecho toda la vida? Y yo que sé. Voy a suponer, de nuevo, que has programado para Android y que sabes cómo se hacen las activitys y demás. Si no lo sabes busca por internet que manuales para empezar hay a patadas.
Para rellenar los spinners es un poquillo complejo, al final todo se arregla picando código, pero si quieres hacer algo especifico (como me pasó a mí, de hecho hay cosas que aún no he sabido arreglar) pues tiene su miga.
Vamos a lo básico. Para crear los objetos de los views en android se hace con findViewById.
Spinner prueba = (Spinner) findViewById(R.id.spinner1);
Ya tenemos el objeto de nuestro spinner. Ahora para poblarlo usamos un ArrayAdapter. Voy a comentar tres formas de hacerlo, dos de ellas bastante populares por internet, poblarla desde un archivo xml de arrays y desde la base de datos SQLite de Android, y una no tan popular pero bastante útil (y más compleja). Después de esto comentaré como obtener los datos elegidos por el usuario y porque me gusta más el tercer método para según qué cosas.
Poblando Spinners
Desde arrays.xml
Bien amigos, para esto necesitamos un archivo arrays.xml con los textos que queramos rellenar en el spinner y un par de líneas de código. El archivo arrays.xml, situado en res/values, tiene el siguiente formato.
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="comidas"> <item>Salchichas</item> <item>Huevos</item> <item>Tomates</item> </string-array> </resources> |
Bien, una vez que tengamos esto vamos a nuestro activity en java y utilizamos el siguiente código que explicaré después.
1 2 3 4 5 6 | //Creamos el adaptador ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,R.array.comidas,android.R.layout.simple_spinner_item); //Añadimos el layout para el menú adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); //Le indicamos al spinner el adaptador a usar prueba.setAdapter(adapter); |
Analicemos línea por línea.
En la primera creamos un ArrayAdapter. Tenemos que indicar entre <> el tipo de objeto que irá dentro del ArrayAdapter para evitar warnings y mejorar la legibilidad del código, en este caso CharSequence.
Este ArrayAdapter lo creamos pasándole como parámetros el contexto, que lo pasamos directamente con this (en otros casos tendrás que hacer un getApplicationContext() ) la referencia a las cadenas de texto que queremos y el layout genérico que proporciona Android para los Spinners.
Con la siguiente línea indicamos el layout, de nuevo genérico de Android, para crear el menú desplegable.
Por último, le añadimos al objeto del spinner el adaptador.
Una vez hecho esto ya tenemos nuestro precioso Spinner listo para entrar al campo a jugar. Vamos a complicarlo un poco más.
Desde SQLite
Android proporciona para nuestro deleite personas una base de datos SQLite. Aquí es posible que tengamos los datos que necesitamos para poblar nuestro Spinner. Vamos a ello.
Me ahorro el explicar cómo crear una base de datos SQLite en android, si necesitáis información sobre cómo manejarla ya sabéis, internet tiene la respuesta, solo diré que está abierta en el objeto baseDatos, que la tabla donde están los datos se llama comidas y la columna con lo que lo vamos a poblar nombres, además de una id.
Vamos con el código.
1 2 3 4 5 6 7 8 | //Creamos el cursor Cursor c = baseDatos.rawQuery("select id AS _id, nombre from comidas", null); //Creamos el adaptador SimpleCursorAdapter adapter2 = new SimpleCursorAdapter(this,android.R.layout.simple_spinner_item,c,new String[] {"nombre"}, new int[] {android.R.id.text1}); //Añadimos el layout para el menú adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); //Le indicamos al spinner el adaptador a usar prueba.setAdapter(adapter2); |
Veamos, con el cursor hacemos un Query a la base de datos. Aquí hay un detalle importante, para que esto funcione necesitamos que la columna del identificador se llame _id, pero, no sé por qué, si la llamas así en la base de datos y luego haces un select normal no funciona, cosas de google (¿un bug?). Con AS funciona estupendamente. El segundo parámetro es para parámetros de selección, como no queremos nada pues le ponemos null.
Vayamos con el adaptador, que tiene tela. Creamos el adaptador en base a un cursor. Los parámetros son el contexto y el layout por defecto, como en el caso anterior, el cursor que hemos creado en la línea anterior, un array de String donde le indicamos que columna es la que tiene que tomar para mostrarlo y de nuevo otro layout por defecto que, sinceramente, no sé muy bien que hace.
Las otras dos líneas son iguales que en el caso del arrays.xml. Así de sencillo, ya tenemos un spinner que nos mostrará los registros de nuestra base de datos. Ahora vamos a complicarlo un poquito más.
Desde un objeto
En ocasiones necesitamos poblar el Spinner con elementos que no están en SQLite o en un array, como puede ser elementos que nos vengan desde una conexión a una base de datos, creados dinámicamente, o lo que sea.
Veamos los ingredientes; un spinner, que ya tenemos, una clase que genere los objetos que queramos, con su toString sobrescrito, unas cuantas líneas similares a las anteriores y sazonar al gusto.
Vamos con la clase de los objetos, que no tiene mucho misterio, pero bueno.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class ObjetosClase{ int id; String nombre; //Constructor public ObjetosClase(int id, String nombre) { super(); this.id = id; this.nombre = nombre; } @Override public String toString() { return nombre; } public int getId() { return id; } } |
Creo que está claro, no hay que explicarlo. El getId lo usaremos en el siguiente punto, paciencia. Vale, ahora a crear el spinner.
1 2 3 4 5 6 7 8 9 10 11 | //Creamos la lista LinkedList<ObjetosClase> comidas = new LinkedList<ObjetosClase>(); //La poblamos con los ejemplos comidas.add(new ObjetosClase(1, "Salchichas")); comidas.add(new ObjetosClase(2, "Huevos")); comidas.add(new ObjetosClase(3, "Tomate")); //Creamos el adaptador ArrayAdapter<ObjetosClase> spinner_adapter = new ArrayAdapter<ObjetosClase>(this, android.R.layout.simple_spinner_item, comidas); //Añadimos el layout para el menú y se lo damos al spinner spinner_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); prueba.setAdapter(spinner_adapter); |
Si controlas un poco de java ves que he creado un nuevo LinkedList y he metido ahí los objetos con las 3 comidas que estamos utilizando.
Después he creado el ArrayAdapter como en el primer caso, solo que esta vez lo hemos creado pasándole el LinkedList. Fijaos que en este caso creamos el ArrayAdapter como cualquier objeto, y que en el primer caso utilizábamos el método estático createFromResource.
El resto ya lo conocemos de sobra. Ya tenemos nuestro spinner con nuestros objetos personalizados. Recordad que lo que toma como nombre es lo que está indicado en el toString.
Obteniendo el dato seleccionado
Ahora que ya tenemos nuestro spinner lleno de datos necesitamos conocer que dato elije el usuario. Para ello tenemos que crear un oyente. En este caso vamos a construirlo para el tercer modo de creación, para obtener el id, para el resto sería igual pero sustituyendo en la línea 4 el código, obteniendo el item y haciéndole toString directamente.
1 2 3 4 5 6 7 8 9 10 11 | public class MyOnItemSelectedListener implements OnItemSelectedListener { public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) { if (parent.getId() == R.id.spinner1) { alimentoId = ((ObjetosClase) parent.getItemAtPosition(pos)).getId(); } //Podemos hacer varios ifs o un switchs por si tenemos varios spinners. } public void onNothingSelected(AdapterView<?> parent) { // Do nothing. } } |
Perfecto, ahora en cuanto un usuario pulse una opción de nuestro spinner se guardará en la variable alimentoId el id de nuestra comida escogida.
Como podéis ver, utilizando nuestros propios objetos es mucho más sencillo recuperar los datos. Podemos crear objetos relativamente grandes, con varios datos, y obtenerlos y tratarlos como queramos en el oyente. Estoy casi seguro que con el primer método también se podría sacar el id (o lo que queramos) de forma muy similar, pero no lo he conseguido.
Bueno hasta aquí el post. Perdonad el largor o longanismo de este, pero seguro que a más de uno le sirve.





junio 2nd, 2011 on 6:26 pm
¡El que me pille la referencia a lo de “largor o longanismo” se lleva un premio! jeje
junio 15th, 2011 on 5:34 pm
Perfecto! funciono…
pero que como podría hacer si quisisera colocar una de las opciones seleccionadas??
estoy usando el metodo de la base de datos…
Gracias.
junio 15th, 2011 on 5:35 pm
¿colocar una de las opciones? ¿Entiendo que quieres ordenar la lista? Si es así puedes usar un ORDER BY en la sentencia SQL y ya esta.
Si es otra cosa lo siento pero no te he entendido.
junio 15th, 2011 on 5:42 pm
me refiero a que aparezca seleccionada una opcion..
haciendo los pasos que indicas aparece siempre seleccionada la primera!
cuando selecciono otra se guarda en una tabla de la BD con el metedo que indicas!
pero cuando vuelvo a entrar en la activity no aparece seleccionada la que seleccione anteriormente sino la primera, y quisiera saber como puedo hacer para que aparezca seleccionada esa que marque.
gracias…
junio 15th, 2011 on 5:47 pm
Puedes utilizar spinner.setSelection(X) en el onCreate para cuando entres a la activity se te seleccione el de la posicion X por defecto.
No encuentro ahora que se pueda hacer de otra forma, pasandole el nombre, pero seguro que hay alguna forma de hacerlo aunque sea indirectamente.
junio 15th, 2011 on 5:53 pm
ummm.. prefiriria algo por el _id pero me sirve por la posicion por ahora!! graciaaaaaaaas!!!
junio 21st, 2011 on 2:49 pm
Necesito llenar un listview.
Intenté adaptar el código pero me da error en la asignación del adaptador.
ListView prueba = (ListView)findViewById(R.id.listView2);
ArrayAdapter adapter =
ArrayAdapter.createFromResource(
this,R.array.comidas ,android.R.layout.activity_list_item);
prueba.setadapter(adapter);
Error en la linea:
prueba.setadapter(adapter);
Me dice “Syntax error on token “adapter”,VariableDeclaratorId expected aqfter this token”
Si me das una mano gracias.
Fedy
agosto 2nd, 2011 on 10:10 pm
largor o longanismo: les luthiers la comision (himnovaciones)
octubre 5th, 2011 on 9:15 am
mae buenisimo! gracias por el aporte!
octubre 26th, 2011 on 6:42 pm
Oye amigo, ya he llenado el spinner desde XML, ahora quiero llenarlo desde SQLite, sin embargo, con la opcion que das me marca un error, mi pregunta es, el parametro String [] (el penultimo) a que hace referencia?
Saludos Gracias =)
octubre 26th, 2011 on 6:45 pm
Con ese array de Strings haces referencia al nombre de las columnas, en este caso a la columna nombres.
octubre 26th, 2011 on 6:48 pm
Aqui te dejo mi codigo, checalo, ya intente poner lo del AS en la consulta pero en SQLite me marca error, asi que no creo que sea por eso porque igual ya lo probe.
Necesito tu ayuda
Spinner cmbPilas=(Spinner) findViewById(R.id.cmbPilas);
DatabaseHelper dbh=new DatabaseHelper(this);
SQLiteDatabase db=dbh.getReadableDatabase();
Cursor pilas = db.rawQuery(“select * from pilas”, null);
//SimpleCursorAdapter c=new
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,android.R.layout.simple_spinner_item,pilas,new String[] {“ID”,”Capacidad”}, new int[] {android.R.id.text1});
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
cmbPilas.setAdapter(adapter);
octubre 26th, 2011 on 6:51 pm
Hace mucho que no utilizo esto, pero se me ocurre que quizás es porque utilices el comodín al crear el cursor, de echo creo que fue uno de mis errores cuando estaba programando un proyecto de este tipo.
Lo dicho, haz el select indicando todos los nombres de las columnas, sin usar comodines.
octubre 26th, 2011 on 7:04 pm
Tampoco, ya lo intente asi “select _idpilas, cantidad from pilas;”, pero ya checaste bien mi codigo?
esta todo bien?
octubre 26th, 2011 on 7:06 pm
El nombre de la columna de id tiene que ser _id, tu la llamas _idpilas. De todos modos, si no es eso pon el error que te da.
octubre 26th, 2011 on 7:19 pm
no such colum: id:, while compilling: select _idpilas, capacidad from pilas;
Si será por eso? Apoco es afuerza que el id se debe llama _id???
octubre 26th, 2011 on 7:43 pm
Si, efectivamente, se tiene que llamar _id, lo puse en el articulo, y es una cosa que me dio mucha lata en su momento.
Si te das cuenta en el error te dice que no encuentra la columna id… mas claro agua jeje
Un saludo.
octubre 30th, 2011 on 12:11 am
final Spinner spinner1=(Spinner)findViewById(R.id.spinner1);
Cursor c = baseDatos.rawQuery (“select _id,razas from perros;”, null);
Hola, mira coloco esto y no funca, si me puedes ayudar… genial con el try catch me tira esto
java.lang.NullPointerException
pero no entiendo que variable esta llegando nula
Gracias…
SimpleCursorAdapter adaptador1=new SimpleCursorAdapter(this,android.R.layout.simple_spinner_item,c,new String[] {“_id”}, new int[] {android.R.id.text1});
adaptador1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner1.setAdapter(adaptador1);
noviembre 19th, 2011 on 12:39 am
Que onda men te vuelvo a dar guerra, ya me salio lo de llenar el spinner, ahora, como podria sacar el valor de un spinner que ha sido llenado desde DB??
Gracias
diciembre 29th, 2011 on 12:10 pm
Post genial, gracias
febrero 22nd, 2012 on 12:38 am
Hola. Muy bueno el articulo. Yo lleno un spinner desde la base de datos. Despues una de las opciones del menu es agregar un fila mas a la tabla que uso para llenar el spinner. Cuando termino de agregar un nuevo registro a la base de datos y vuelvo a la pantalla del spinner, este spinner no esta actualizo. Como puedo hacer para actualizarlo automaticamente?