SwingWorker en Java 5

Puede ver una versión activa de este post en mi nuevo blog. He decidido dejar de publicar en este blog por éstas razones. Su filosofía es la misma que éste, pero espero no tener los problemas que me he encontrado aquí.

SwingWorker es una clase de utilidad incluida en Java SE 6 que soluciona el problema de utilizar un hilo (thread) separado al de Swing para realizar tareas de larga duración. Anteriormente ya existían implementaciones que realizaban esta tarea, pero en la versión 6 de Java SE se ha decidido incluirla en la propia distribución de Java. Existe un backport de SwingWorker para utilizar los mismos conceptos en Java SE 5. Esta entrada es aplicable tanto para SwingWorker incluido en Java SE 6 como para el backport.

El hilo manejador de eventos (Event Dispatching Thread)

Durante el desarrollo de interfaces gráficas suelen aparecer tareas cuya realización conllevan mucho tiempo, por ejemplo, leer un archivo XML cuando el usuario pulse un botón. La forma más rápida y sencilla de realizar esta tarea podría ser los siguiente:

JButton button = new JButton("Cargar fichero XML");
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        xmlDocument = loadXML();
    }
});

De esta forma, la carga del archivo se realiza en el hilo manejador de eventos (EDT – Event Dispatching Thread) de Swing, y como la tarea necesita mucho tiempo, no es posible manejar el resto de eventos que la interfaz gráfica genera y se quedara congelado, fijo, sin respuesta aparente, hasta que la tarea finalice. Esto produce un efecto indeseable de cara al usuario de la aplicación.

De hecho, a la hora de desarrollar interfaces gráficas se deberían respetar estas dos reglas básicas:

  • Las tareas de larga duración no deben ejecutarse nunca en el hilo manejador de eventos (EDT), de otra forma la aplicación no responderá al usuario.
  • Los componentes gráficos se deben acceder únicamente desde el hilo manejador de eventos.

Cualquier otra debería realizarse en un hilo separado (difícil pero es lo más recomendable).

Solución

Efectivamente, la solución pasa por utilizar un hilo distinto al EDT. SwingWorker nos proporciona la base para utilizar un hilo distinto para realizar tareas costosas en cuanto al tiempo de ejecución. SwingWorker permite ejecutar tareas de larga duración mientras la interfaz gráfica sigue respondiendo a la interacción con el usuario.

La forma más simple de utilizar SwingWorker es implementando el método doInBackground extendiendo la clase SwingWorker o creando una clase anónima:

SwingWorker worker = new SwingWorker<MyXMLFile, Void>() {
public MyXMLFile doInBackground() {
MyXMLFile myXMLDoc = loadXML();
return myXMLDoc;
}
};

Para que la tarea se ejecute debemos invocar al método execute de SwingWorker. Dicho método se encarga de llamar a doInBackground asegurándose de que se ejecuta en un hilo diferente al EDT.

Pero, ¿cómo recupero el resultado de la larga tarea?. SwingWorker proporciona el método get para recuperar el resultado, pero sólo debe ser llamado una vez la tarea ha finalizado. Existen dos métodos para asegurarnos que la tarea ha finalizado:

  1. Sobrescribiendo el método done, el cual es ejecutado en el hilo manejador de eventos después de que la tarea haya finalizado.
    private MyXMLFile doc;
    //...
    SwingWorker<Document, Void> worker = new SwingWorker<MyXMLFile, Void>() {
    public MyXMLFile doInBackground() {
    MyXMLFile myXMLDoc = loadXML();
    return myXMLDoc;
    }
    public void done() {
    doc = get();
    }
    };
    
  2. Registrar un listener mediante el método addPropertyChangeListener(PropertyChangeListener listener) el cual será notificado de cambios en el estado de SwingWorker.
    Actualización (26-01-2010): Uso avanzado de SwingWorker
Anuncios

Etiquetas: ,

3 responses to “SwingWorker en Java 5”

  1. Juan Manuel Carballo says :

    Vaya interesante no sabia que existia esa clase en java, y yo que siempre utilizaba threads normales para actualizar el GUI, ahora ya se que no se debe hacer asi

    • txingo says :

      No es que no se puedan utilizar threads normales para realizar este tipo de tareas, pero SwingWorker ya nos da una base para poder utilizar threads distintos al Event Dispatching Thread de una forma muy sencilla y uniforme en toda nuestra aplicación.
      Espero haberte servido de ayuda.

Trackbacks / Pingbacks

  1. Uso avanzado de SwingWorker « Ruben ChT's Blog - 26 enero 2010

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: