Está en la página 1de 32

SALVADOR GMEZ OLIVER

WWW.SGOLIVER.NET



Versin 2.0 // Noviembre 2011

Este documento y todo el cdigo fuente suministrado, al igual que todos los contenidos
publicados en el blog sgoliver.net, se publica bajo licencia Creative Commons Reconocimiento
NoComercial - SinObraDerivada 3.0 Espaa (CC BY-NC-ND 3.0). Siga el enlace anterior para
obtener informacin detallada sobre los trminos de la licencia indicada.

DOCUMENTO DE MUESTRA
Este documento es tan slo un fragmento de muestra del
Curso completo de Programacin en Android de
sgoliver.net, al que podis acceder de forma gratuita
desde la siguiente URL:

http://www.sgoliver.net/blog/?p=1313


NDICE DE CONTENIDOS

PRLOGO ................................................................................................................................ 5
A QUIN VA DIRIGIDO ESTE LIBRO? .....................................................................................6
LICENCIA .................................................................................................................................6
Conceptos Bsicos .................................................................................................................. 7
Entorno de desarrollo Android ..................................................................................... 8
Estructura de un proyecto Android ............................................................................ 12
Componentes de una aplicacin Android ................................................................... 15
Desarrollando una aplicacin Android sencilla ........................................................... 17
Interfaz de Usuario ................................................................................................................ 24
Layouts ...................................................................................................................... 25
Botones ...................................................................................................................... 29
Imgenes, etiquetas y cuadros de texto ..................................................................... 32
Checkboxes y RadioButtons ....................................................................................... 36
Listas Desplegables .................................................................................................... 38
Listas.......................................................................................................................... 42
Optimizacin de listas ................................................................................................ 47
Grids .......................................................................................................................... 50
Pestaas .................................................................................................................... 52
Controles personalizados: Extender controles ........................................................... 56
Controles personalizados: Combinar controles .......................................................... 59
Controles personalizados: Diseo completo .............................................................. 67
Widgets de Escritorio ............................................................................................................ 74
Widgets bsicos ......................................................................................................... 75
Widgets avanzados .................................................................................................... 79
Mens .................................................................................................................................... 88
Mens y Submens bsicos ........................................................................................ 89
Mens Contextuales ................................................................................................... 94
Opciones avanzadas de men .................................................................................... 98
Tratamiento de XML ........................................................................................................... 105
Tratamiento de XML con SAX .................................................................................. 106
Tratamiento de XML con SAX Simplificado .............................................................. 112
Tratamiento de XML con DOM ................................................................................ 115


Tratamiento de XML con XmlPull ............................................................................. 120
Bases de Datos .................................................................................................................... 123
Primeros pasos con SQLite ...................................................................................... 124
Insertar/Actualizar/Eliminar ..................................................................................... 129
Consultar/Recuperar registros .................................................................................. 131
Preferencias ......................................................................................................................... 134
Preferencias Compartidas ........................................................................................ 135
Pantallas de Preferencias ......................................................................................... 137
Localizacin Geogrfica ...................................................................................................... 145
Localizacin Geogrfica Bsica ................................................................................ 146
Profundizando en la Localizacin Geogrfica ........................................................... 152
Mapas .................................................................................................................................. 159
Preparativos y ejemplo bsico .................................................................................. 160
Control MapView ..................................................................................................... 167
Overlays (Capas) ...................................................................................................... 172
Ficheros ............................................................................................................................... 178
Ficheros en Memoria Interna .................................................................................... 179
Ficheros en Memoria Externa (Tarjeta SD) ............................................................... 182
Content Providers ............................................................................................................... 187
Construccin de Content Providers .......................................................................... 188
Utilizacin de Content Providers .............................................................................. 197
Notificaciones ..................................................................................................................... 203
Notificaciones Toast ................................................................................................ 204
Notificaciones de la Barra de Estado ........................................................................ 205
Cuadros de Dilogo .................................................................................................. 213
Depuracin de aplicaciones ................................................................................................ 219
Logging en Android.................................................................................................. 220




PRLOGO
Hay proyectos que se comienzan sin saber muy bien el rumbo exacto que se tomar, ni el
destino que se pretende alcanzar. Proyectos cuyo nico impulso es el da a da, sin planes, sin
reglas, tan solo con el entusiasmo de seguir adelante, a veces con ganas, a veces sin fuerzas,
pero siempre con la intuicin de que va a salir bien.
El papel bajo estas lneas es uno de esos proyectos. Naci casi de la casualidad all por 2010.
Hoy estamos viendo como acaba el 2011 y sigue ms vivo que nunca.
A pesar de llevar metido en el desarrollo para Android casi desde sus inicios, en mi blog
[sgoliver.net] nunca haba tratado estos temas, pretenda mantenerme fiel a su temtica
original: el desarrollo bajo las plataformas Java y .NET. Surgieron en algn momento algunos
escarceos con otros lenguajes, pero siempre con un ojo puesto en los dos primeros.
Mi formacin en Android fue en ingls. No haba alternativa, era el nico idioma en el que, por
aquel entonces, exista buena documentacin sobre la plataforma. Desde el primer concepto
hasta el ltimo tuve que aprenderlo en el idioma de Shakespeare. A da de hoy esto no ha
cambiado mucho, la buena documentacin sobre Android, la buena de verdad, sigue y seguir
an durante algn tiempo estando en ingls, pero afortunadamente son ya muchas las
personas de habla hispana las que se estn ocupando de ir equilibrando poco a poco esta
balanza de idiomas.
Y con ese afn de aportar un pequeo granito de arena a la comunidad hispanohablante es
como acab decidiendo dar un giro, quien sabe si temporal o permanente, a mi blog y
comenzar a escribir sobre desarrollo para la plataforma Android. No saba hasta dnde iba a
llegar, no saba la aceptacin que tendra, pero lo que s saba es que me apeteca ayudar un
poco a los que como yo les costaba encontrar informacin bsica sobre Android disponible en
su idioma.
Hoy, gracias a todo vuestro apoyo, vuestra colaboracin, vuestras propuestas, y vuestras
crticas (de todo se aprende) ste es un proyecto con ms de un ao ya de vida. Ms de 250
pginas, ms de 40 artculos, y sobre todo cientos de comentarios de nimo recibidos.
Y este documento no es un final, es slo un punto y seguido. Este libro es tan solo la mejor
forma que he encontrado de mirar atrs, ordenar ideas, y pensar en el siguiente camino a
tomar, que espero sea largo. Espero que muchos de vosotros me acompais en parte de ese
camino igual que lo habis hecho en el recorrido hasta ahora.
Muchas gracias, y que comience el espectculo.



A QUIN VA DIRIGIDO ESTE LIBRO?
Este manual va dirigido a todas aquellas personas interesadas en un tema tan en auge como la
programacin de aplicaciones mviles para la plataforma Android. Se tratarn temas
dedicados a la construccin de aplicaciones nativas de la plataforma, dejando a un lado por el
momento las aplicaciones web. Es por ello por lo que el nico requisito indispensable a la hora
de utilizar este manual es tener conocimientos bien asentados sobre el lenguaje de
programacin Java y ciertas nociones sobre aspectos bsicos del desarrollo actual como la
orientacin a objetos.
LICENCIA
Este documento y todo el cdigo fuente suministrado, al igual que todos los contenidos
publicados en el blog sgoliver.net, se publica bajo licencia Creative Commons
Reconocimiento NoComercial - SinObraDerivada 3.0 Espaa (CC BY-NC-ND 3.0). Siga
el enlace anterior para obtener informacin detallada sobre los trminos de la licencia
indicada.







DOCUMENTO DE MUESTRA
Este documento es tan slo un fragmento de muestra del
Curso completo de Programacin en Android de
sgoliver.net, al que podis acceder de forma gratuita
desde la siguiente URL:

http://www.sgoliver.net/blog/?p=1313


III. Widgets
Widgets bsicos
En los dos prximos apartados del curso vamos a describir detalladamente cmo crear un
widget de escritorio (home screen widget).
En esta primera parte construiremos un widget esttico (no ser interactivo, ni contendr
datos actualizables, ni responder a eventos) muy bsico para entender claramente la
estructura interna de un componente de este tipo, y en el siguiente apartado completaremos
el ejercicio aadiendo una ventana de configuracin inicial para el widget, aadiremos algn
dato que podamos actualizar peridicamente, y haremos que responda a pulsaciones del
usuario.
Como hemos dicho, en esta primera parte vamos a crear un widget muy bsico, consistente en
un simple marco rectangular negro con un mensaje de texto predeterminado (Mi Primer
Widget). La sencillez del ejemplo nos permitir centrarnos en los pasos principales de la
construccin de un widget Android y olvidarnos de otros detalles que nada tienen que ver con
el tema que nos ocupa (grficos, datos, ). Para que os hagis una idea, ste ser el aspecto
final de nuestro widget de ejemplo:



Los pasos principales para la creacin de un widget Android son los siguientes:
1. Definicin de su interfaz grfica (layout).
2. Configuracin XML del widget (AppWidgetProviderInfo).
3. Implementacin de la funcionalidad del widget (AppWidgetProvider) ,
especialmente su evento de actualizacin.
4. Declaracin del widget en el Android Manifest de la aplicacin.
En el primer paso no nos vamos a detener mucho ya que es anlogo a cualquier definicin de
layout de las que hemos visto hasta ahora en el curso. En esta ocasin, la interfaz del widget
estar compuesta nicamente por un par de frames (FrameLayout), uno negro exterior y
uno blanco interior algo ms pequeo para simular el marco, y una etiqueta de texto
(TextView) que albergar el mensaje a mostrar. Veamos cmo queda el layout xml, que
para este ejemplo llamaremos miwidget.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dip">

<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#000000"
android:padding="10dip" >

<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF"
android:padding="5dip" >

<TextView android:id="@+id/txtMensaje"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:textColor="#000000"
android:text="Mi Primer Widget" />

</FrameLayout>

</FrameLayout>

</LinearLayout>
Cabe destacar aqu que, debido a que el layout de los widgets de Android est basado en un
tipo especial de componentes llamados RemoteViews, no es posible utilizar en su interfaz
todos los contenedores y controles que hemos visto en artculos anteriores sino unos pocos
bsicos que se indican a continuacin:
Contenedores: FrameLayout, LinearLayout y RelativeLayout
Controles: Button, ImageButton, ImageView, TextView, ProgressBar,
Chronometer y AnalogClock.
Aunque la lista de controles soportados no deja de ser curiosa (al menos en mi humilde
opinin), debera ser suficiente para crear todo tipo de widgets.


Como segundo paso del proceso de construccin vamos a crear un nuevo fichero XML donde
definiremos un conjunto de propiedades del widget, como por ejemplo su tamao en pantalla
o su frecuencia de actualizacin. Este XML se deber crear en la carpeta \res\xml de
nuestro proyecto.
En nuestro caso de ejemplo lo llamaremos miwidget_wprovider.xml y tendr la
siguiente estructura:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/miwidget"
android:minWidth="146dip"
android:minHeight="72dip"
android:label="Mi Primer Widget"
android:updatePeriodMillis="3600000"
/>
Para nuestro widget estamos definiendo las siguientes propiedades:
initialLayout: referencia al layout XML que hemos creado en el paso anterior.
minWidth: ancho mnimo del widget en pantalla, en dp (density-independent pixels).
minHeight: alto mnimo del widget en pantalla, en dp (density-independent pixels).
label: nombre del widget que se mostrar en el men de seleccin de Android.
updatePeriodMillis: frecuencia de actualizacin del widget, en milisegundos.
Existen varias propiedades ms que se pueden definir. En el siguiente artculo utilizaremos
alguna de ellas, el resto se pueden consultar en la documentacin oficial de la clase
AppWidgetProviderInfo.
Como sabemos, la pantalla inicial de Android se divide en 44 celdas donde se pueden colocar
aplicaciones, accesos directos y widgets. Teniendo en cuenta las diferentes dimensiones de
estas celdas segn la orientacin de la pantalla, existe una frmula sencilla para ajustar las
dimensiones de nuestro widget para que ocupe un nmero determinado de celdas sea cual
sea la orientacin:
ancho_mnimo = (num_celdas * 74) 2
alto_mnimo = (num_celdas * 74) 2
Atendiendo a esta frmula, si queremos que nuestro widget ocupe un tamao mnimo de 2
celdas de ancho por 1 celda de alto, deberemos indicar unas dimensiones de 146dp x 72dp.
Vamos ahora con el tercer paso. ste consiste en implementar la funcionalidad de nuestro
widget en su clase java asociada. Esta clase deber heredar de AppWidgetProvider, que a
su vez no es ms que una clase auxiliar derivada de BroadcastReceiver, ya que los
widgets de Android no son ms que un caso particular de este tipo de componentes.




En esta clase deberemos implementar los mensajes a los que vamos a responder desde
nuestro widget, entre los que destacan:
onEnabled(): lanzado cuando se aade al escritorio la primera instancia de un
widget.
onUpdate(): lanzado peridicamente cada vez que se debe actualizar un widget.
onDeleted(): lanzado cuando se elimina del escritorio una instancia de un widget.
onDisabled(): lanzado cuando se elimina del escritorio la ltima instancia de un
widget.
En la mayora de los casos, tendremos que implementar como mnimo el evento
onUpdate(). El resto de mtodos dependern de la funcionalidad de nuestro widget. En
nuestro caso particular no nos har falta ninguno de ellos ya que el widget que estamos
creando no contiene ningn dato actualizable, por lo que crearemos la clase, llamada
MiWidget, pero dejaremos vaco por el momento el mtodo onUpdate(). En el siguiente
apartado veremos qu cosas podemos hacer dentro de estos mtodos.
package net.sgoliver.android;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;

public class MiWidget extends AppWidgetProvider {
@Override
public void onUpdate(Context context,
AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
//Actualizar el widget
//...
}
}
El ltimo paso del proceso ser declarar el widget dentro del manifest de nuestra aplicacin.
Para ello, editaremos el fichero AndroidManifest.xml para incluir la siguiente declaracin
dentro del elemento <application>:
<application>
...
<receiver android:name=".MiWidget" android:label="Mi Primer Widget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/miwidget_wprovider" />
</receiver>
</application>





El widget se declarar como un elemento <receiver> y deberemos aportar la siguiente
informacin:
Atributo name: Referencia a la clase java de nuestro widget, creada en el paso
anterior.
Elemento <intent-filter>, donde indicaremos los eventos a los que
responder nuestro widget, normalmente aadiremos el evento
APPWIDGET_UPDATE, para detectar la accin de actualizacin.
Elemento <meta-data>, donde haremos referencia con su atributo resource al
XML de configuracin que creamos en el segundo paso del proceso.
Con esto habramos terminado de escribir los distintos elementos necesarios para hacer
funcionar nuestro widget bsico de ejemplo. Para probarlo, podemos ejecutar el proyecto de
Eclipse en el emulador de Android, esperar a que se ejecute la aplicacin principal (que estar
vaca, ya que no hemos incluido ninguna funcionalidad para ella), ir a la pantalla principal del
emulador y aadir nuestro widget al escritorio tal cmo lo haramos en nuestro telfono
(pulsacin larga sobre el escritorio o tecla Men, seleccionar la opcin Widgets, y por ltimo
seleccionar nuestro Widget). Os dejo una demostracin en video (Nota: se trata de un enlace a
YouTube, se necesita conexin a internet para poder visualizarlo).
Como podis ver en el video, ya hemos conseguido la funcionalidad bsica de un widget, es
posible aadir varias instancias al escritorio, desplazarlos por la pantalla y eliminarlos
envindolos a la papelera.
En el prximo artculo veremos cmo podemos mejorar este widget aadiendo una pantalla
de configuracin inicial, mostraremos algn dato que se actualice peridicamente, y
aadiremos la posibilidad de capturar eventos de pulsacin sobre el widget.

El cdigo fuente completo de este artculo est disponible entre los ejemplos suministrados con el
manual.
Fichero: /Codigo/android-widgets-1.zip








Widgets avanzados
Hemos visto ya cmo construir un widget bsico para Android, y prometimos que
dedicaramos un artculo adicional a comentar algunas caractersticas ms avanzadas de este
tipo de componentes. Pues bien, en este segundo apartado sobre el tema vamos a ver cmo
podemos aadir los siguientes elementos y funcionalidades al widget bsico que ya
construimos:
Pantalla de configuracin inicial.
Datos actualizables de forma peridica.
Eventos de usuario.
Como sabis, intento simplificar al mximo todos los ejemplos que utilizo en este curso para
que podamos centrar nuestra atencin en los aspectos realmente importantes. En esta
ocasin utilizar el mismo criterio y las nicas caractersticas (aunque suficientes para
demostrar los tres conceptos anteriores) que aadiremos a nuestro widget sern las
siguientes:
1. Aadiremos una pantalla de configuracin inicial del widget, que aparecer cada vez
que se aada una nueva instancia del widget a nuestro escritorio. En esta pantalla
podr configurarse nicamente el mensaje de texto a mostrar en el widget.
2. Aadiremos un nuevo elemento de texto al widget que muestre la hora actual. Esto
nos servir para comprobar que el widget se actualiza peridicamente.
3. Aadiremos un botn al widget, que al ser pulsado forzar la actualizacin inmediata
del mismo.
Empecemos por el primer punto, la pantalla de configuracin inicial del widget. Y
procederemos igual que para el diseo de cualquier otra actividad Android, definiendo su
layout xml. En nuestro caso ser muy sencilla, un cuadro de texto para introducir el mensaje a
personalizar y dos botones, uno para aceptar la configuracin y otro para cancelar (en cuyo
caso el widget no se aade al escritorio). En esta ocasin llamaremos a este layout
widget_config.xml. Veamos cmo queda:
<?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="fill_parent"
android:orientation="vertical">

<TextView android:id="@+id/LblMensaje"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mensaje personalizado:" />

<EditText android:id="@+id/TxtMensaje"
android:layout_height="wrap_content"
android:layout_width="fill_parent" />

<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >



<Button android:id="@+id/BtnAceptar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Aceptar" />

<Button android:id="@+id/BtnCancelar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancelar" />

</LinearLayout>

</LinearLayout>
Una vez diseada la interfaz de nuestra actividad de configuracin tendremos que
implementar su funcionalidad en java. Llamaremos a la clase WidgetConfig, su estructura
ser anloga a la de cualquier actividad de Android, y las acciones a realizar sern las
comentadas a continuacin. En primer lugar nos har falta el identificador de la instancia
concreta del widget que se configurar con esta actividad. Este ID nos llega como parmetro
del intent que ha lanzado la actividad. Como ya vimos en un artculo anterior del curso, este
intent se puede recuperar mediante el mtodo getIntent() y sus parmetros mediante el
mtodo getExtras(). Conseguida la lista de parmetros del intent, obtendremos el valor
del ID del widget accediendo a la clave AppWidgetManager.EXTRA_APPWIDGET_ID.
Veamos el cdigo hasta este momento:
public class WidgetConfig extends Activity {

private int widgetId = 0;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.widget_config);

//Obtenemos el Intent que ha lanzado esta ventana
//y recuperamos sus parmetros
Intent intentOrigen = getIntent();
Bundle params = intentOrigen.getExtras();

//Obtenemos el ID del widget que se est configurando
widgetId = params.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);

//Establecemos el resultado por defecto (si se pulsa el botn 'Atrs'
//del telfono ser ste el resultado devuelto).
setResult(RESULT_CANCELED);

//...
}
}
En el cdigo tambin podemos ver como aprovechamos este momento para establecer el
resultado por defecto a devolver por la actividad de configuracin mediante el mtodo
setResult(). Esto es importante porque las actividades de configuracin de widgets
deben devolver siempre un resultado (RESULT_OK en caso de aceptarse la configuracin, o
RESULT_CANCELED en caso de salir de la configuracin sin aceptar los cambios).


Estableciendo aqu ya un resultado RESULT_CANCELED por defecto nos aseguramos de que
si el usuario sale de la configuracin pulsando el botn Atrs del telfono no aadiremos el
widget al escritorio, mismo resultado que si pulsramos el botn Cancelar de nuestra
actividad.
Como siguiente paso recuperamos las referencias a cada uno de los controles de la actividad
de configuracin:
//Obtenemos la referencia a los controles de la pantalla
final Button btnAceptar = (Button)findViewById(R.id.BtnAceptar);
final Button btnCancelar = (Button)findViewById(R.id.BtnCancelar);
final EditText txtMensaje = (EditText)findViewById(R.id.TxtMensaje);
Por ltimo, implementaremos las acciones de los botones Aceptar y Cancelar. En
principio, el botn Cancelar no tendra por qu hacer nada, tan slo finalizar la actividad
mediante una llamada al mtodo finish() ya que el resultado CANCELED ya se ha
establecido por defecto anteriormente:
//Implementacin del botn "Cancelar"
btnCancelar.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
//Devolvemos como resultado: CANCELAR (RESULT_CANCELED)
finish();
}
});
En el caso del botn Aceptar tendremos que hacer ms cosas:
1. Guardar de alguna forma el mensaje que ha introducido el usuario.
2. Actualizar manualmente la interfaz del widget segn la configuracin establecida.
3. Devolver el resultado RESULT_OK aportando adems el ID del widget.
Para el primer punto nos ayudaremos de la API de Preferencias que describimos en el artculo
anterior. En nuestro caso, guardaremos una sola preferencia cuya clave seguir el patrn
msg_IdWidget, esto nos permitir distinguir el mensaje configurado para cada instancia
del widget que aadamos a nuestro escritorio de Android.
El segundo paso indicado es necesario debido a que si definimos una actividad de
configuracin para un widget, ser sta la que tenga la responsabilidad de realizar la primera
actualizacin del mismo en caso de ser necesario. Es decir, tras salir de la actividad de
configuracin no se lanzar automticamente el evento onUpdate() del widget (s se
lanzar posteriormente y de forma peridica segn la configuracin del parmetro
updatePeriodMillis del provider que veremos ms adelante), sino que tendr que ser la
propia actividad quien fuerce la primera actualizacin. Para ello, simplemente obtendremos
una referencia al widget manager de nuestro contexto mediente el mtodo
AppWidgetManager.getInstance() y con esta referencia llamaremos al mtodo
esttico de actualizacin del widget MiWidget.actualizarWidget(), que actualizar
los datos de todos los controles del widget (lo veremos un poco ms adelante).


Por ltimo, al resultado a devolver (RESULT_OK) deberemos aadir informacin sobre el ID
de nuestro widget. Esto lo conseguimos creando un nuevo Intent que contenga como
parmetro el ID del widget que recuperamos antes y establecindolo como resultado de la
actividad mediante el mtodo setResult(resultado, intent). Por ltimo
llamaremos al mtodo finish() para finalizar la actividad. Con estas indicaciones, veamos
cmo quedara el cdigo del botn Aceptar:
//Implementacin del botn "Aceptar"
btnAceptar.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
//Guardamos el mensaje personalizado en las preferencias
SharedPreferences prefs =
getSharedPreferences("WidgetPrefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("msg_" + widgetId,
txtMensaje.getText().toString());
editor.commit();

//Actualizamos el widget tras la configuracin
AppWidgetManager appWidgetManager =
AppWidgetManager.getInstance(WidgetConfig.this);
MiWidget.actualizarWidget(WidgetConfig.this,
appWidgetManager, widgetId);

//Devolvemos como resultado: ACEPTAR (RESULT_OK)
Intent resultado = new Intent();
resultado.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
setResult(RESULT_OK, resultado);
finish();
}
});
Ya hemos terminado de implementar nuestra actividad de configuracin. Pero para su
correcto funcionamiento an nos quedan dos detalles ms por modificar. En primer lugar
tendremos que declarar esta actividad en nuestro fichero AndroidManifest.xml,
indicando que debe responder a los mensajes de tipo APPWIDGET_CONFIGURE:
<activity android:name=".WidgetConfig">
<intent-filter>
<action android:name="android.apwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
Por ltimo, debemos indicar en el XML de configuracin de nuestro widget
(xml\miwidget_wprovider.xml) que al aadir una instancia de este widget debe
mostrarse la actividad de configuracin que hemos creado. Esto se consigue estableciendo el
atributo android:configure del provider. Aprovecharemos adems este paso para
establecer el tiempo de actualizacin automtica del widget al mnimo permitido por este
parmetro (30 minutos) y el tamao del widget a 22 celdas. Veamos cmo quedara
finalmente:




<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/miwidget"
android:minWidth="146dip"
android:minHeight="146dip"
android:label="Mi Primer Widget"
android:updatePeriodMillis="1800000"
android:configure="net.sgoliver.android.WidgetConfig"
/>
Con esto, ya tenemos todo listo para que al aadir nuestro widget al escritorio se muestre
automticamente la pantalla de configuracin que hemos construido. Podemos ejecutar el
proyecto en este punto y comprobar que todo funciona correctamente.
Como siguiente paso vamos a modificar el layout del widget que ya construimos en el artculo
anterior para aadir una nueva etiqueta de texto donde mostraremos la hora actual, y un
botn que nos servir para forzar la actualizacin de los datos del widget:
<?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="fill_parent"
android:padding="5dip">

<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#000000"
android:padding="10dip" >

<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF"
android:padding="5dip"
android:orientation="vertical">

<TextView android:id="@+id/LblMensaje"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:text="mensaje" />

<TextView android:id="@+id/LblHora"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:text="hora_actual" />

<Button android:id="@+id/BtnActualizar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Actualizar" />

</LinearLayout>

</FrameLayout>

</LinearLayout>


Hecho esto, tendremos que modificar la implementacin de nuestro provider
(MiWidget.java) para que en cada actualizacin del widget se actualicen sus controles con
los datos correctos (recordemos que en el artculo anterior dejamos este evento de
actualizacin vaco ya que no mostrbamos datos actualizables en el widget). Esto lo haremos
dentro del evento onUpdate() de nuestro provider.
Como ya dijimos, los componentes de un widget se basan en un tipo especial de vistas que
llamamos Remote Views. Pues bien, para acceder a la lista de estos componentes que
constituyen la interfaz del widget construiremos un nuevo objeto RemoteViews a partir del
ID del layout de cada widget. Obtenida la lista de componentes, tendremos disponibles una
serie de mtodos set (uno para cada tipo de datos bsicos) para establecer las propiedades de
cada control del widget. Estos mtodos reciben como parmetros el ID del control, el nombre
del mtodo que queremos ejecutar sobre el control, y el valor a establecer. Adems de estos
mtodos, contamos adicionalmente con una serie de mtodos ms especficos para
establecer directamente el texto y otras propiedades sencillas de los controles TextView,
ImageView, ProgressBar y Chronometer, como por ejemplo
setTextViewText(idControl, valor) para establecer el texto de un control
TextView. Pueden consultarse todos los mtodos disponibles en la documentacin oficial
de la clase RemoteViews. De esta forma, si por ejemplo queremos establecer el texto del
control cuyo id es LblMensaje haramos lo siguiente:
RemoteViews controles = new RemoteViews(context.getPackageName(),
R.layout.miwidget);
controles.setTextViewText(R.id.LblMensaje, "Mensaje de prueba");
El proceso de actualizacin habr que realizarlo por supuesto para todas las instancias del
widget que se hayan aadido al escritorio. Recordemos aqu que el evento onUpdate()
recibe como parmetro la lista de widgets que hay que actualizar.
Dicho esto, creo que ya podemos mostrar cmo quedara el cdigo de actualizacin de
nuestro widget:
@Override
public void onUpdate(Context context,
AppWidgetManager appWidgetManager,
int[] appWidgetIds) {

//Iteramos la lista de widgets en ejecucin
for (int i = 0; i < appWidgetIds.length; i++)
{
//ID del widget actual
int widgetId = appWidgetIds[i];

//Actualizamos el widget actual
actualizarWidget(context, appWidgetManager, widgetId);
}
}


public static void actualizarWidget(Context context,
AppWidgetManager appWidgetManager, int widgetId)
{
//Recuperamos el mensaje personalizado para el widget actual
SharedPreferences prefs =


context.getSharedPreferences("WidgetPrefs", Context.MODE_PRIVATE);

String mensaje = prefs.getString("msg_" + widgetId, "Hora actual:");

//Obtenemos la lista de controles del widget actual
RemoteViews controles =
new RemoteViews(context.getPackageName(), R.layout.miwidget);

//Actualizamos el mensaje en el control del widget
controles.setTextViewText(R.id.LblMsg, mensaje);

//Obtenemos la hora actual
Calendar calendario = new GregorianCalendar();
String hora = calendario.getTime().toLocaleString();

//Actualizamos la hora en el control del widget
controles.setTextViewText(R.id.LblHora, hora);

//Notificamos al manager de la actualizacin del widget actual
appWidgetManager.updateAppWidget(widgetId, controles);
}
Como vemos, todo el trabajo de actualizacin para un widget lo hemos extrado a un mtodo
esttico independiente, de forma que tambin podamos llamarlo desde otras partes de la
aplicacin (como hacemos por ejemplo desde la actividad de configuracin para forzar la
primera actualizacin del widget).
Adems quiero destacar la ltima lnea del cdigo, donde llamamos al mtodo
updateAppWidget() del widget manager. Esto es importante y necesario, ya que de no
hacerlo la actualizacin de los controles no se reflejar correctamente en la interfaz del
widget.
Tras esto, ya slo nos queda implementar la funcionalidad del nuevo botn que hemos
incluido en el widget para poder forzar la actualizacin del mismo. A los controles utilizados
en los widgets de Android, que ya sabemos que son del tipo RemoteView, no podemos
asociar eventos de la forma tradicional que hemos visto en mltiples ocasiones durante el
curso. Sin embargo, en su lugar, tenemos la posibilidad de asociar a un evento (por ejemplo, el
click sobre un botn) un determinado mensaje (Pending Intent) de tipo broadcast que ser
lanzado cada vez que se produzca dicho evento. Adems, podremos configurar el widget (que
como ya indicamos no es ms que un componente de tipo broadcast receiver) para que capture
esos mensajes, e implementar en el evento onReceive() del widget las acciones necesarias
a ejecutar tras capturar el mensaje. Con estas tres acciones simularemos la captura de eventos
sobre controles de un widget.
Vamos por partes. En primer lugar hagamos que se lance un intent broadcast cada vez que se
pulse el botn del widget. Para ello, en el mtodo actualizarWidget() construiremos un
nuevo Intent asocindole una accin personalizada, que en nuestro caso llamaremos por
ejemplo net.sgoliver.ACTUALIZAR_WIDGET. Como parmetro del nuevo Intent
insertaremos mediante putExtra() el ID del widget actual de forma que ms tarde podamos
saber el widget concreto que ha lanzado el mensaje. Por ltimo crearemos el
PendingIntent mediante el mtodo getBroadcast() y lo asociaremos al evento
onClick del control llamando a setOnClickPendingIntent() pasndole el ID del
control, en nuestro caso el botn de Actualizar. Veamos cmo queda todo esto:


//Asociamos los 'eventos' al widget
Intent intent = new Intent("net.sgoliver.ACTUALIZAR_WIDGET");
intent.putExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);

PendingIntent pendingIntent =
PendingIntent.getBroadcast(context, widgetId,
intent, PendingIntent.FLAG_UPDATE_CURRENT);

controles.setOnClickPendingIntent(R.id.BtnActualizar, pendingIntent);
Ahora vamos a declarar en el Android Manifest este mensaje personalizado, de forma que el
widget sea capaz de capturarlo. Para ello, aadiremos simplemente un nuevo elemento
<intent-filter> con nuestro nombre de accin personalizado:
<intent-filter>
<action android:name="net.sgoliver.ACTUALIZAR_WIDGET"/>
</intent-filter>
Por ltimo, vamos a implementar el evento onReceive() del widget para actuar en caso de
recibir nuestro mensaje de actualizacin personalizado. Dentro de este evento
comprobaremos si la accin del mensaje recibido es la nuestra, y en ese caso recuperaremos
el ID del widget que lo ha lanzado, obtendremos una referencia al widget manager, y por
ltimo llamaremos nuestro mtodo esttico de actualizacin pasndole estos datos.
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("net.sgoliver.ACTUALIZAR_WIDGET")) {
//Obtenemos el ID del widget a actualizar
int widgetId = intent.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);

//Obtenemos el widget manager de nuestro contexto
AppWidgetManager widgetManager =
AppWidgetManager.getInstance(context);

//Actualizamos el widget
if (widgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
actualizarWidget(context, widgetManager, widgetId);
}
}
Con esto, por fin, hemos ya finalizado la construccin de nuestro widget android y podemos
ejecutar el proyecto de Eclipse para comprobar que todo funciona correctamente, tanto para
una sola instancia como para varias instancias simultaneas.
Un comentario final, la actualizacin automtica del widget se ha establecido a la frecuencia
mnima que permite el atributo updatePeriodMillis del widget provider, que son 30
minutos. Por tanto es difcil y aburrido esperar para verla en funcionamiento mientras
probamos el widget en el emulador. Pero funciona, os lo aseguro. De cualquier forma, esos 30
minutos pueden ser un periodo demasiado largo de tiempo segn la funcionalidad que
queramos dar a nuestro widget, que puede requerir tiempos de actualizacin mucho ms
cortos (ojo con el rendimiento y el gasto de batera). Ms adelante, cuando hablemos de
Alarmas, veremos una tcnica que nos permitir actualizar los widgets sin esa limitacin de 30


minutos. Hasta entonces, espero que el tema os sea de utilidad y que os haya parecido
interesante.

El cdigo fuente completo de este artculo est disponible entre los ejemplos suministrados con el
manual.
Fichero: /Codigo/android-widgets-2.zip





DOCUMENTO DE MUESTRA
Este documento es tan slo un fragmento de muestra del
Curso completo de Programacin en Android de
sgoliver.net, al que podis acceder de forma gratuita
desde la siguiente URL:

http://www.sgoliver.net/blog/?p=1313


VII. Preferencias en Android
Preferencias Compartidas
En este apartado vamos hablar de un tema que nos ser de ayuda ms adelante para la
construccin de cualquier tipo de aplicacin Android. Este tema es la administracin de
preferencias.
Las preferencias no son ms que datos que una aplicacin debe guardar para personalizar la
experiencia del usuario, por ejemplo informacin personal, opciones de presentacin, etc. En
artculos anteriores vimos ya uno de los mtodos disponibles en la plataforma Android para
almacenar datos, como son las bases de datos SQLite. Las preferencias de una aplicacin se
podran almacenar por su puesto utilizando este mtodo, y no tendra nada de malo, pero
Android proporciona otro mtodo alternativo diseado especficamente para administrar este
tipo de datos: las preferencias compartidas o shared preferences. Cada preferencia se
almacenar en forma de clave-valor, es decir, cada una de ellas estar compuesta por un
identificador nico (p.e. email) y un valor asociado a dicho identificador (p.e.
prueba@email.com). Adems, y a diferencia de SQLite, los datos no se guardan en un
fichero de binario de base de datos, sino en ficheros XML como veremos al final de este
artculo.
La API para el manejo de estas preferencias es muy sencilla. Toda la gestin se centraliza en la
clase SharedPrefences, que representar a una coleccin de preferencias. Una aplicacin
Android puede gestionar varias colecciones de preferencias, que se diferenciarn mediante un
identificador nico. Para obtener una referencia a una coleccin determinada utilizaremos el
mtodo getSharedPrefences() al que pasaremos el identificador de la coleccin y un
modo de acceso. El modo de acceso indicar qu aplicaciones tendrn acceso a la coleccin de
preferencias y qu operaciones tendrn permitido realizar sobre ellas. As, tendremos tres
posibilidades principales:
MODE_PRIVATE. Slo nuestra aplicacin tiene acceso a estas preferencias.
MODE_WORLD_READABLE. Todas las aplicaciones pueden leer estas preferencias,
pero slo la nuestra modificarlas.
MODE_WORLD_WRITABLE. Todas las aplicaciones pueden leer y modificar estas
preferencias.
Teniendo todo esto en cuenta, para obtener una referencia a una coleccin de preferencias
llamada por ejemplo MisPreferencias y como modo de acceso exclusivo para nuestra
aplicacin haramos lo siguiente:
SharedPreferences prefs =
getSharedPreferences("MisPreferencias",Context.MODE_PRIVATE);



Una vez hemos obtenido una referencia a nuestra coleccin de preferencias, ya podemos
obtener, insertar o modificar preferencias utilizando los mtodos get o put
correspondientes al tipo de dato de cada preferencia. As, por ejemplo, para obtener el valor
de una preferencia llamada email de tipo String escribiramos lo siguiente:
SharedPreferences prefs =
getSharedPreferences("MisPreferencias",Context.MODE_PRIVATE);

String correo = prefs.getString("email", "por_defecto@email.com");
Como vemos, al mtodo getString() le pasamos el nombre de la preferencia que
queremos recuperar y un segundo parmetro con un valor por defecto. Este valor por defecto
ser el devuelto por el mtodo getString() si la preferencia solicitada no existe en la
coleccin. Adems del mtodo getString(), existen por supuesto mtodos anlogos para
el resto de tipos de datos bsicos, por ejemplo getInt(), getLong(), getFloat(),
getBoolean(),
Para actualizar o insertar nuevas preferencias el proceso ser igual de sencillo, con la nica
diferencia de que la actualizacin o insercin no la haremos directamente sobre el objeto
SharedPreferences, sino sobre su objeto de edicin SharedPreferences.Editor.
A este ltimo objeto accedemos mediante el mtodo edit() de la clase
SharedPreferences. Una vez obtenida la referencia al editor, utilizaremos los mtodos
put correspondientes al tipo de datos de cada preferencia para actualizar/insertar su valor,
por ejemplo putString(clave, valor), para actualizar una preferencia de tipo
String. De forma anloga a los mtodos get que ya hemos visto, tendremos disponibles
mtodos put para todos los tipos de datos bsicos: putInt(), putFloat(),
putBoolean(), etc. Finalmente, una vez actualizados/insertados todos los datos necesarios
llamaremos al mtodo commit() para confirmar los cambios. Veamos un ejemplo sencillo:
SharedPreferences prefs =
getSharedPreferences("MisPreferencias",Context.MODE_PRIVATE);

SharedPreferences.Editor editor = prefs.edit();
editor.putString("email", "modificado@email.com");
editor.putString("nombre", "Prueba");
editor.commit();
Dnde se almacenan estas preferencias compartidas? Como dijimos al comienzo del artculo,
las preferencias no se almacenan en ficheros binarios como las bases de datos SQLite, sino en
ficheros XML. Estos ficheros XML se almacenan en una ruta con el siguiente patrn:
/data/data/paquetejava/shared_prefs/nombre_coleccion.xml
As, por ejemplo, en nuestro caso encontraramos nuestro fichero de preferencias en la ruta:
/data/data/net.sgoliver.android/shared_prefs/MisPreferencias.xml



Si descargamos este fichero desde el DDMS y lo abrimos con cualquier editor de texto
veremos un contenido como el siguiente:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="nombre">prueba</string>
<string name="email">modificado@email.com</string>
</map>
En este XML podemos observar cmo se han almacenado las dos preferencias de ejemplo que
insertamos anteriormente, con sus claves y valores correspondientes.
Y nada ms, as de fcil y prctico. Con esto hemos aprendido una forma sencilla de
almacenar determinadas opciones de nuestra aplicacin sin tener que recurrir para ello a
definir bases de datos SQLite, que aunque tampoco aaden mucha dificultad s que requieren
algo ms de trabajo por nuestra parte.
En una segunda parte de este tema dedicado a las preferencias veremos cmo Android nos
ofrece otra forma de gestionar estos datos, que se integra adems fcilmente con la interfaz
grfica necesaria para solicitar los datos al usuario.

Pantallas de Preferencias
Hemos dedicado el apartado anterior a las preferencias compartidas (shared preferences), un
mecanismo que nos permite gestionar fcilmente las opciones de una aplicacin
permitindonos guardarlas en XML de una forma transparente para el programador. Sin
embargo, slo hemos visto cmo hacer uso de ellas mediante cdigo, es decir, creando
nosotros mismos los objetos necesarios (SharedPreferences) y aadiendo, modificando
y/o recuperando a mano los valores de las opciones a travs de los mtodos
correspondientes (getString(), putString(), ). Pero ya avisamos de que Android
ofrece una forma alternativa de definir mediante XML un conjunto de opciones para una
aplicacin y crear por nosotros las pantallas necesarias para permitir al usuario modificarlas a
su antojo. A esto dedicaremos este segundo apartado sobre preferencias.
Si nos fijamos en cualquier pantalla de preferencias estndar de Android veremos que todas
comparten una interfaz comn, similar por ejemplo a la que se muestra en la imagen siguiente
(correspondiente a la pantalla de opciones de la galera de imgenes de Android).



Si observamos la imagen anterior vemos cmo las diferentes opciones se organizan dentro de
la pantalla de opciones en varias categoras (General Settings y Slideshow Settings).
Dentro de cada categora pueden aparecer varias opciones de diversos tipos, como por
ejemplo de tipo checkbox (Confirm deletions) o de tipo lista de seleccin (Display size). He
resaltado las palabras pantalla de opciones, categoras, y tipos de opcin porque sern
estos los tres elementos principales con los que vamos a definir el conjunto de opciones o
preferencias de nuestra aplicacin. Empecemos.
Como hemos indicado, nuestra pantalla de opciones la vamos a definir mediante un XML, de
forma similar a como definimos cualquier layout, aunque en este caso deberemos colocarlo en
la carpeta /res/xml. El contenedor principal de nuestra pantalla de preferencias ser el
elemento <PreferenceScreen>. Este elemento representar a la pantalla de opciones en
s, dentro de la cual incluiremos el resto de elementos. Dentro de ste podremos incluir
nuestra lista de opciones organizadas por categoras, que se representar mediante el
elemento <PreferenceCategory> al que daremos un texto descriptivo utilizando su
atributo android:title.




Dentro de cada categora podremos aadir cualquier nmero de opciones, las cuales pueden
ser de distintos tipos, entre los que destacan:
Tipo Descripcin
CheckBoxPreference Marca seleccionable.
EditTextPreference Cadena simple de texto.
ListPreference Lista de valores seleccionables (exclusiva).
MultiSelectListPreference Lista de valores seleccionables (mltiple).

Cada uno de estos tipos de preferencia requiere la definicin de diferentes atributos, que
iremos viendo en los siguientes apartados.
CheckBoxPreference
Representa un tipo de opcin que slo puede tomar dos valores distintos: activada o
desactivada. Es el equivalente a un control de tipo checkbox. En este caso tan slo tendremos
que especificar los atributos: nombre interno de la opcin (android:key), texto a mostrar
(android:title) y descripcin de la opcin (android:summary). Veamos un ejemplo:
<CheckBoxPreference
android:key="opcion1"
android:title="Preferencia 1"
android:summary="Descripcin de la preferencia 1" />
EditTextPreference
Representa un tipo de opcin que puede contener como valor una cadena de texto. Al pulsar
sobre una opcin de este tipo se mostrar un cuadro de dilogo sencillo que solicitar al
usuario el texto a almacenar. Para este tipo, adems de los tres atributos comunes a todas las
opciones (key, title y summary) tambin tendremos que indicar el texto a mostrar en el
cuadro de dilogo, mediante el atributo android:dialogTitle. Un ejemplo sera el
siguiente:
<EditTextPreference
android:key="opcion2"
android:title="Preferencia 2"
android:summary="Descripcin de la preferencia 2"
android:dialogTitle="Introduce valor" />
ListPreference
Representa un tipo de opcin que puede tomar como valor un elemento, y slo uno,
seleccionado por el usuario entre una lista de valores predefinida. Al pulsar sobre una opcin
de este tipo se mostrar la lista de valores posibles y el usuario podr seleccionar uno de ellos.
Y en este caso seguimos aadiendo atributos. Adems de los cuatro ya comentados (key,
title, summary y dialogTitle) tendremos que aadir dos ms, uno de ellos indicando
la lista de valores a visualizar en la lista y el otro indicando los valores internos que


utilizaremos para cada uno de los valores de la lista anterior (Ejemplo: al usuario podemos
mostrar una lista con los valores Espaol y Francs, pero internamente almacenarlos como
ESP y FRA).
Estas listas de valores las definiremos tambin como ficheros XML dentro de la carpeta
/res/xml. Definiremos para ello los recursos de tipos <string-array> necesarios, en
este caso dos, uno para la lista de valores visibles y otro para la lista de valores internos, cada
uno de ellos con su ID nico correspondiente. Veamos cmo quedaran dos listas de ejemplo,
en un fichero llamado codigospaises.xml:
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<string-array name="pais">
<item>Espaa</item>
<item>Francia</item>
<item>Alemania</item>
</string-array>
<string-array name="codigopais">
<item>ESP</item>
<item>FRA</item>
<item>ALE</item>
</string-array>
</resources>
En la preferencia utilizaremos los atributos android:entries y
android:entryValues para hacer referencia a estas listas, como vemos en el ejemplo
siguiente:
<ListPreference
android:key="opcion3"
android:title="Preferencia 3"
android:summary="Descripcin de la preferencia 3"
android:dialogTitle="Indicar Pais"
android:entries="@array/pais"
android:entryValues="@array/codigopais" />
MultiSelectListPreference
[A partir de Android 3.0.x / Honeycomb] Las opciones de este tipo son muy similares a las
ListPreference, con la diferencia de que el usuario puede seleccionar varias de las
opciones de la lista de posibles valores. Los atributos a asignar son por tanto los mismos que
para el tipo anterior.
<MultiSelectListPreference
android:key="opcion4"
android:title="Preferencia 4"
android:summary="Descripcin de la preferencia 4"
android:dialogTitle="Indicar Pais"
android:entries="@array/pais"
android:entryValues="@array/codigopais" />
Como ejemplo completo, veamos cmo quedara definida una pantalla de opciones con las 3
primeras opciones comentadas (ya que probar con Android 2.2), divididas en 2 categoras


llamadas por simplicidad Categora 1 y Categora 2. Llamaremos al fichero
opciones.xml.
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="Categora 1">
<CheckBoxPreference
android:key="opcion1"
android:title="Preferencia 1"
android:summary="Descripcin de la preferencia 1" />
<EditTextPreference
android:key="opcion2"
android:title="Preferencia 2"
android:summary="Descripcin de la preferencia 2"
android:dialogTitle="Introduce valor" />
</PreferenceCategory>
<PreferenceCategory android:title="Categora 2">
<ListPreference
android:key="opcion3"
android:title="Preferencia 3"
android:summary="Descripcin de la preferencia 3"
android:dialogTitle="Indicar Pais"
android:entries="@array/pais"
android:entryValues="@array/codigopais" />
</PreferenceCategory>
</PreferenceScreen>
Ya tenemos definida la estructura de nuestra pantalla de opciones, pero an nos queda un
paso ms para poder hacer uso de ella desde nuestra aplicacin. Adems de la definicin XML
de la lista de opciones, debemos implementar una nueva actividad, que ser a la que hagamos
referencia cuando queramos mostrar nuestra pantalla de opciones y la que se encargar
internamente de gestionar todas las opciones, guardarlas, modificarlas, etc, a partir de
nuestra definicin XML.
Android nos facilita las cosas ofrecindonos una clase de la que podemos derivar fcilmente la
nuestra propia y que hace todo el trabajo por nosotros. Esta clase se llama
PreferenceActivity. Tan slo deberemos crear una nueva actividad (yo la he llamado
PantallaOpciones) que extienda a esta clase e implementar su evento onCreate()
para aadir una llamada al mtodo addPreferencesFromResource(), mediante el que
indicaremos el fichero XML en el que hemos definido la pantalla de opciones. Lo vemos mejor
directamente en el cdigo:
public class PantallaOpciones extends PreferenceActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

addPreferencesFromResource(R.xml.opciones);
}
}
As de sencillo, nuestra nueva actividad, al extender a PreferenceActivity, se encargar
por nosotros de crear la interfaz grfica de nuestra lista de opciones segn la hemos definido
en el XML y se preocupar por nosotros de mostrar, modificar y guardar las opciones cuando
sea necesario tras la accin del usuario.


Por supuesto, tendremos que aadir esta actividad al fichero AndroidManifest.xml, al
igual que cualquier otra actividad que utilicemos en la aplicacin.
<activity android:name=".PantallaOpciones"
android:label="@string/app_name">
</activity>
Ya slo nos queda aadir a nuestra aplicacin algn mecanismo para mostrar la pantalla de
preferencias. Esta opcin suele estar en un men, pero por simplificar el ejemplo vamos a
aadir simplemente un botn (btnPreferencias) que llame a la ventana de preferencias.
Al pulsar este botn llamaremos a la ventana de preferencias mediante el mtodo
startActivity(), como ya hemos visto en alguna ocasin, al que pasaremos como
parmetros el contexto de la aplicacin (nos vale con nuestra actividad principal) y la clase de
la ventana de preferencias (PantallaOpciones.class).
btnPreferencias = (Button)findViewById(R.id.BtnPreferencias);

btnPreferencias.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(AndroidPrefScreensActivity.this,
PantallaOpciones.class));
}
});
Y esto es todo, ya slo nos queda ejecutar la aplicacin en el emulador y pulsar el botn de
preferencias para mostrar nuestra nueva pantalla de opciones. Debe quedar como muestra la
imagen siguiente:



La primera opcin podemos marcarla o desmarcarla directamente pulsando sobre la check de
su derecha. La segunda, de tipo texto, nos mostrar al pulsarla un pequeo formulario para
solicitar el valor de la opcin.

Por ltimo, la opcin 3 de tipo lista, nos mostrar una ventana emergente con la lista de
valores posibles, donde podremos seleccionar slo uno de ellos.



Una vez establecidos los valores de las preferencias podemos salir de la ventana de opciones
simplemente pulsando el botn Atrs del dispositivo o del emulador. Nuestra actividad
PantallaOpciones se habr ocupado por nosotros de guardar correctamente los valores
de las opciones haciendo uso de la API de preferencias compartidas (Shared Preferences). Y
para comprobarlo vamos a aadir otro botn (btnObtenerOpciones) a la aplicacin de
ejemplo que recupere el valor actual de las 3 preferencias y los escriba al log de la aplicacin.
La forma de acceder a las preferencias compartidas de la aplicacin ya la vimos en el artculo
anterior sobre este tema. Obtenemos la lista de preferencias mediante el mtodo
getDefaultSharedPreferences() y posteriormente utilizamos los distintos mtodos
get() para recuperar el valor de cada opcin dependiendo de su tipo.
btnObtenerPreferencias.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences pref =
PreferenceManager.getDefaultSharedPreferences(
AndroidPrefScreensActivity.this);

Log.i("", "Opcin 1: " + pref.getBoolean("opcion1", false));
Log.i("", "Opcin 2: " + pref.getString("opcion2", ""));
Log.i("", "Opcin 3: " + pref.getString("opcion3", ""));
}
});
Si ejecutamos ahora la aplicacin, establecemos las preferencias y pulsamos el nuevo botn
de consulta que hemos creado veremos cmo en el log de la aplicacin aparecen los valores
correctos de cada preferencia. Se mostrara algo como lo siguiente:
10-08 09:27:09.681: INFO/(1162): Opcin 1: true
10-08 09:27:09.681: INFO/(1162): Opcin 2: prueba
10-08 09:27:09.693: INFO/(1162): Opcin 3: FRA
Y hasta aqu hemos llegado con el tema de las preferencias, un tema muy interesante de
controlar ya que casi ninguna aplicacin se libra de hacer uso de ellas.

El cdigo fuente completo de este artculo est disponible entre los ejemplos suministrados con el
manual.
Fichero: /Codigo/android-pref-activity.zip


DOCUMENTO DE MUESTRA
Este documento es tan slo un fragmento de muestra del
Curso completo de Programacin en Android de
sgoliver.net, al que podis acceder de forma gratuita
desde la siguiente URL:

http://www.sgoliver.net/blog/?p=1313

También podría gustarte