Figura 4.2. Modificación de la UI con View.post.
4.3. Modificación de la UI con Handler.post
Una tercera forma de modificar la interfaz de usuario consiste en usar un controlador, u objeto de la clase Handler. A este objeto le pasaremos un objeto Runnable mediante el método Handler.post(), que lo añade al hilo principal. En el siguiente ejemplo, que es una variación de los dos anteriores, se explica el modo de hacerlo. El resultado se muestra en la figura 4.3. (ver Android para otros ejemplos del uso de la clase Handler pasándole un mensaje).
Figura 4.3. Modificación de la UI con Handler.
4.4. Métodos combinados para modificar la UI
Los tres métodos anteriores, usando RunOnUiThread(), View.post() y Handler.post(), pueden combinarse como en el siguiente ejemplo, donde abrimos tres hilos, cada uno de los cuales varía el color de un texto de forma aleatoria. Para ello modificamos la clase CambiaTexto de los ejemplos anteriores añadiéndole dos parámetros: el texto a modificar y un número que se utiliza para cambiar las componentes RGB del color mediante un algoritmo. En la figura 4.4. se muestra el resultado.
El layout, definido en el siguiente fichero main.xml, contiene tres TextView.
A continuación se detalla el fichero Java de la actividad CambiaColor.
Figura 4.4. Tres hilos simultáneos cambiando el color de un texto.
4.5. Modificación de la UI con AsyncTask
La clase AsyncTask permite realizar tareas en background y publicar los resultados en la interfaz de usuario sin necesidad de crear hilos y sincronizarlos con la UI. Para utilizarla hay que definir una subclase, que toma tres parámetros genéricos (ver Apéndice B, secciones B.3 y B.4 sobre el uso de genéricos en Java).
Aquí, X, Y, Z son tres nombres de clases utilizados para los datos del input, progreso y resultado, respectivamente. La clase anterior debe sobrescribir necesariamente el método doInBackground, que admite un número variable de parámetros de tipo X y devuelve un dato de tipo Z (ver Apéndice B, en el que se discuten los métodos de Java con un número variable de parámetros).
El método doInBackground se ejecuta en un nuevo hilo. Desde este hilo se pueden publicar actualizaciones en el hilo principal llamando al método publishProgress(Y … progreso). Entonces, el hilo principal se encarga de invocar el método onProgressUpdate(Y … progreso). Al finalizar la ejecución del proceso en background, el hilo principal invoca el método onPostExecute(Z resultado).
En el siguiente ejemplo se ilustra el uso de AsyncTask, donde un contador se incrementa desde 0 hasta 99 y en cada paso mostramos su valor en un objeto TextView en la pantalla, aumentando proporcionalmente su tamaño. Al final de la ejecución se añade el texto «Fin», como se muestra en la figura 4.5.
Figura 4.5. Uso de AsyncTask para ejecutar un proceso en background y publicar su progreso en el hilo principal.
4.6. Máquina tragaperras
El siguiente ejemplo es una aplicación práctica de AsyncTask para ejecutar varios hilos simultáneamente. Se trata de un juego que simula una máquina tragaperras. La actividad slotMachine consiste en tres columnas de imágenes que van permutando simulando la rotación de imágenes en cada uno de los tres rodillos de una máquina tragaperras. Cada columna se pone en marcha o se para independientemente por medio un botón que, al ser pulsado, cambia el valor de la variable de control continuar[columna]. Si esta es true, ejecuta un nuevo proceso AsyncTask para mostrar las imágenes en movimiento. Si es false, el proceso AsyncTask se detiene automáticamente. La clase AsyncTask definida más abajo requiere como parámetro de entrada el número de columna. Cada vez que se ejecuta onPostExecute, se determina si los tres procesos se han detenido, en cuyo caso comprueba si las imágenes de la segunda fila coinciden. En caso afirmativo, se escribe el mensaje «¡¡¡PREMIO!!!» en la pantalla.
Además, se han añadido tres botones que permiten controlar la velocidad del movimiento de las imágenes, incrementando o disminuyendo el valor de la variable dificultad, que no es más que el tiempo, en microsegundos, que cada imagen se muestra en pantalla.
El layout de esta aplicación consiste en una tabla con tres columnas. Previamente se han copiado las nueve imágenes jpg (de tragaperras1.jpg a tragaperras9.jpg) en el directorio de recursos res/drawable-hdpi de nuestra aplicación. Las imágenes son cuadradas con 250 píxeles de lado.
El fichero main. xml es el siguiente:
A continuación se detalla el fichero TragaPerras.java. La secuencia de las nueve imágenes, que se ha almacenado en la matriz secuencia[3][9], es diferente en cada columna. En la figura 4.6. se muestran