Platform.runLater y Task en JavaFX

88

He estado investigando un poco sobre esto, pero todavía estoy MUY confundido por decir lo menos.

¿Alguien puede darme un ejemplo concreto de cuándo usar Tasky cuándo usar Platform.runLater(Runnable);? ¿Cuál es exactamente la diferencia? ¿Existe una regla de oro sobre cuándo usar alguno de estos?

También corríjame si me equivoco, pero ¿no son estos dos "Objetos" una forma de crear otro hilo dentro del hilo principal en una GUI (usada para actualizar la GUI)?

Marc Rasmussen
fuente

Respuestas:

108

Úselo Platform.runLater(...)para operaciones rápidas y simples y Taskpara operaciones complejas y grandes.

Ejemplo: ¿Por qué no podemos usarlo Platform.runLater(...)para cálculos largos? (Tomado de la referencia a continuación).

Problema: hilo en segundo plano que solo cuenta de 0 a 1 millón y actualiza la barra de progreso en la interfaz de usuario.

Código usando Platform.runLater(...):

final ProgressBar bar = new ProgressBar();
new Thread(new Runnable() {
    @Override public void run() {
    for (int i = 1; i <= 1000000; i++) {
        final int counter = i;
        Platform.runLater(new Runnable() {
            @Override public void run() {
                bar.setProgress(counter / 1000000.0);
            }
        });
    }
}).start();

Este es un horrible trozo de código, un crimen contra la naturaleza (y la programación en general). Primero, perderá células cerebrales con solo mirar este doble anidamiento de Runnables. En segundo lugar, inundará la cola de eventos con pequeños Runnables, de hecho, un millón de ellos. Claramente, necesitábamos alguna API para facilitar la escritura de trabajadores en segundo plano que luego se comunican con la interfaz de usuario.

Código usando Task:

Task task = new Task<Void>() {
    @Override public Void call() {
        static final int max = 1000000;
        for (int i = 1; i <= max; i++) {
            updateProgress(i, max);
        }
        return null;
    }
};

ProgressBar bar = new ProgressBar();
bar.progressProperty().bind(task.progressProperty());
new Thread(task).start();

no tiene ninguno de los defectos exhibidos en el código anterior

Referencia: Worker Threading en JavaFX 2.0

invariante
fuente
El ejemplo de tarea en el enlace de la aplicación Ensemble ya no funcionará.
Cugomastik
Este es el enlace correcto, pero no puedo editarlo porque la edición tiene solo 2 caracteres.
Aerus
29
Decir que una para operaciones "rápidas" y otra para operaciones "complejas" es un poco engañoso. La principal diferencia, después de todo, es que uno permite ejecutar código en el hilo de la GUI de JFX desde otro lugar, y el otro hace exactamente lo contrario: permite ejecutar código en el hilo de fondo desde el hilo de la GUI (agregando una ventaja de ser capaz de comunicarse con el hilo de la GUI en el proceso).
Sergei Tachenov
Quiero guardar una imagen de cada una de las escenas, y esto llevará tiempo. ¿Eso causará problemas cuando se ejecute en un hilo separado a través de Task? Entendí que todo el trabajo relacionado con la interfaz gráfica de usuario debe realizarse en el hilo de FxApplication.
StephenBoesch
@ Sergey-Tachenov ¿Entonces usas runLater () de un hilo de Tarea para actualizar el hilo de la GUI en los casos en los que quieres hacer algo más que actualizar una sola propiedad como el progreso?
simpleuser
58
  • Platform.runLater: Si necesita actualizar un componente GUI desde un subproceso que no es GUI, puede usarlo para poner su actualización en una cola y será manejada por el subproceso GUI tan pronto como sea posible.
  • Taskimplementa la Workerinterfaz que se usa cuando necesita ejecutar una tarea larga fuera del hilo de la GUI (para evitar congelar su aplicación) pero aún necesita interactuar con la GUI en algún momento.

Si está familiarizado con Swing, el primero equivale SwingUtilities.invokeLatery el segundo al concepto de SwingWorker.

El javadoc de Task da muchos ejemplos que deberían aclarar cómo se pueden usar. También puede consultar el tutorial sobre simultaneidad .

Assylias
fuente
Gracias ¿Puede dar un pequeño ejemplo de cómo utilizar la plataforma? ¿Puedes usarlo fuera del hilo de la interfaz gráfica de usuario o? Y los ejemplos de tareas en los documentos son realmente confusos
Marc Rasmussen
Sí, Platform.runLater se puede usar fuera del hilo de la GUI, ese es su propósito principal. Puede encontrar este tutorial sobre tareas más informativo que el javadoc.
Assylias
3
Platform.runLater(new Runnable() {public void run() {updateYourGuiHere();}});
Usas
¿cómo podré usar los componentes de la GUI entonces =: S
Marc Rasmussen
1
@KevinMeredith El método de llamada de Task no debe ser llamado en el hilo FX, pero Task proporciona métodos puente (updateProgress, etc.) que se ejecutan en el hilo FX. Consulte los tutoriales y javadoc para obtener más información.
Assylias
12

Ahora se puede cambiar a la versión lambda.

@Override
public void actionPerformed(ActionEvent e) {
    Platform.runLater(() -> {
        try {
            //an event with a button maybe
            System.out.println("button is clicked");
        } catch (IOException | COSVisitorException ex) {
            Exceptions.printStackTrace(ex);
        }
    });
}
Cugomastik
fuente
8
Si está manejando un evento de GUI, está en el hilo de GUI. ¿Por qué usarías runLater () entonces?
TFuto
Si bien tiene razón, la respuesta de Caglar fue tratar de resaltar el uso de una expresión lambda, no necesariamente para dar un buen ejemplo de codificación. Yo usoPlatform.runLater(() -> progressBar.setProgress(X/Y));
Taelsin
2

Una razón para usar un Platform.runLater () explícito podría ser que vinculó una propiedad en la interfaz de usuario a una propiedad de servicio (resultado). Entonces, si actualiza la propiedad del servicio vinculado, debe hacerlo a través de runLater ():

En el hilo de la interfaz de usuario también conocido como hilo de la aplicación JavaFX:

...    
listView.itemsProperty().bind(myListService.resultProperty());
...

en la implementación del servicio (trabajador en segundo plano):

...
Platform.runLater(() -> result.add("Element " + finalI));
...
Alexander Pietsch
fuente