ThreadingHandler Runnable & Messages

En este ejercicio implementaremos las dos formas de ejecutar procesos en trheads gestionados por los Handlers, veremos cómo gestionar Handlers con Runnables y con Messages.

ThreadingHandlerRunnable

Crear un nuevo proyecto llamado ThreadingHandlerRunnable con el código y layouts del proyecto ThreadingAsyncTask.

Modificar el código para:

  • En la actividad principal instanciar un nuevo objeto Handler privado a la clase.
  • En el listener del botón “Load Icon” instanciar y ejecutar un thread cuyo código será un Runnable que vamos a crear a continuación.
  • La clase LoadIconTask en este ejercicio será un Runnable y no un AsyncTask como el ejercicio anterior.
  • En el constructor del Runnable LoadIconTask pasarle el ID del recurso a cargar, es decir el R.drawable.painter.
  • El método run() del Runnable LoadIconTask deberá realizar varias tareas, pero la ejecución de éstas no se realizará en el mismo thread donde se ejecuta este Runnable, sino que serán Runnables que se enviarán al Handler de la actividad principal para su ejecución.

Por tanto habrá que definir, internamenete o anónimamente los Runnables apropiados para:

  • Hacer visible la barra de progreso
  • Establecer el bitmap ya cargado en la vista apropiada
  • Establecer el progreso de la barra de tareas cada cierto tiempo
  • Hacer invisible la barra de progreso

La “operación pesada” que realizará el Runnable LoadIconTask será la carga del bitmap, al igual que en los ejercicios anteriores simulando su carga durante un tiempo de 5 segundos, simulando con un bucle llamando al método sleep(). La notificación de progreso se realizará cada vez que venza el delay.

ThreadingHandlerMessages

Crear un nuevo proyecto llamado ThreadingHandlerMessage con el código y layouts del proyecto ThreadingHandlerRunnable.

Se trata de modificar el código para que en vez de enviar Runnables al Handler de la actividad principal, envíe Messages y que éstos sean procesados por el método handleMessage del Handler.

Par ello:

  • Modificar el constructor del Runnable LoadIconTask para que reciba como parámetro adicionalmente el handler apropiado.
  • Modificar el Runnable LoadIconTask de forma que para cada Runnable que enviábamos antes, ahora creemos un mensaje y enviemos el mensaje. Por tanto, los Runnables ya no hacen falta.
  • Para crear los Messages haremos uso del método (ver documentación)
public final Message obtainMessage (int what, Object obj)

El int what serán constantes definidas por nosotros, llamadas:

  • SET_PROGRESS_BAR_VISIBILITY para los mensajes que indican la visibilidad la barra de progreso
  • PROGRESS_UPDATE para el mensaje que indica el avance de la barra de progreso
  • SET_BITMAP para el mensaje que indica que se puede establecer el bitmap ya cargado.
  • El obj que se envía con cada mensaje varía en función del tipo de mensaje.
  • La constante apropiada para establecer la visibilidad o quitarla de un objeto ProgressBar, para los mensajes SET_PROGRESS_BAR_VISIBILITY.
  • Un objeto Bitmap, (el que se carga desde el recurso pasado en el constructor), para SET_BITMAP
  • Un entero para los mensajes PROGRESS_UPDATE.

En este ejercicio hay que sobrecargar el siguiente método del Handler instanciado para la clase principal que debe responder con un switch a los distintos mensajes.

public void handleMessage(Message msg)

Tener en cuenta que el Message msg tiene toda la información, así con msg.what obtenemos el mensaje de que se trata y con msg.obj el objeto que se pasa como segundo parámetro en función del tipo de mensaje.
Atención: Debemos hacer un casting para tratar msg.obj, por ejemplo (Integer) msg.obj para obtener el entero que indica el avance de la barra de progreso.

Os dejo el código de los ejercicios resueltos

Mejoras

La clase LoadIconTask vemos en el código que es privada a la Activity con la que estamos trabajando. Podríamos crear una clase pública a nivel de Package para que funcione independientemente de la actividad que estemos utilizando. Para hacer esto podéis crear otra activity y utilizar la misma clase LoadIconTask que le de servicio a ambas.

Os dejo el código con la solución a las mejoras, está resuelto para runnables, os dejo como ejercicio resolverlo para messages. Fijaros que durante la carga de la imagen podemos ir a la siguiente actividad, lanzar en ella también la carga de la imagen y en background sigue realizándose la carga de la imagen en la Main Activity.