Ejemplo de Swing Worker: ¿Por qué se me congela la interfaz?

Ejemplo de Swing Worker: ¿Por qué se me congela la interfaz?

0. Índice de contenidos.

1. Entorno

Este tutorial está escrito usando el siguiente entorno:
  • Hardware: Portátil Mac Book Pro 17″ (2,6 Ghz Intel Core i7, 8 GB DDR3)
  • Sistema Operativo: Mac OS X Snow Leopard 10.6.4
  • Maven 2.2.1
  • Eclipse 3.6 (Helios) con M2Eclipse
  • jdk 1.6

2. Introducción

Una de las tareas más comunes que tenemos que hacer cuando desarrollamos con Swing es la de actualizar la interfaz en función de los procesos que se van produciendo. En muchas ocasiones nos encontramos con la sorpresa de que la interfaz no se actualiza en el momento, si no que parece congelarse y sólo acaba actualizándose cuando el proceso finaliza.

La explicación a este fenómeno es sencilla, Swing todos los eventos relacionados con la interfaz los gestiona como una cola FIFO en un hilo independiente, conocido con el nombre de EDT (Event Dispatching Thread). Por tanto, si nosotros ejecutamos tareas pesadas dentro del radio de actuación de este hilo, estaremos bloqueando el resto de peticiones de actualización de la interfaz.

Para evitar bloquear el hilo EDT, Swing nos proporciona una clase llamada SwingWorker, que lo que hace es abrir otro hilo para ejecutar la tarea pesada, y así no bloquear el EDT.

3. Para muestra un botón… o mejor dos

Para demostrar este funcionamiento vamos a crear un proyecto donde vamos a tener un pantalla con un campo de texto y dos botones. El primer botón va a ejecutar su acción sin la utilización de Swing Worker y el segundo si va a utilizar Swing Worker.

Este es el código para la ventana comentada:

Si nos fijamos en el método main de esta clase, veremos la utilización de la clase SwingUtilities, más concretamente el método invokeLater. Este método precisamente lo que hace es que el proceso que implementa se encole en la lista de eventos pendiente del hilo EDT. Una buena práctica es que todos los métodos que afecten a la interfaz gráfica, se ejecuten dentro de un invokeLater, para asegurarnos de que la gestión del hilo EDT se está haciendo correctamente.

La acción que ejecutan los dos botones va a ser la misma, ambos van a mostrar en el cuadro texto la cuenta ascendente de una variable hasta que se iguale al valor de la constante MAX_ITE.

En primer lugar vamos a desarrollar la acción sin el uso de Swing Worker:

Si ahora ejecutamos la segunda acción veremos que el campo se actualiza casi secuencialmente hasta que llega al valor de MAX_ITE. Con lo que el problema queda resuelto, ya que la tarea se ejecuta en un hilo independiente y no bloquea el EDT. Otra forma de resolver el problema es crear nosotros mismos el hilo con la interfaz Runnable, pero si ya existe una forma estándar de hacerlo, mejor usamos la clase Swing Worker.

4. Conclusiones

Con esto espero haber ayudado a todos aquellos a los que una vez no supimos porque nuestra aplicación Swing no se comportaba como nosotros esperábamos.

Saludos.