threads runlater hilos example concurrencia java exception-handling thread-safety javafx-2

runlater - javafx, actualizar ui desde otro hilo



runlater javafx (2)

Tengo una aplicación javafx y un subproceso de trabajo, implementado a través de javafx.concurrent.Task , que realiza un proceso largo, que consiste en comprimir y cargar un conjunto de archivos.
He conectado el progreso de la tarea a una barra de progressProperty través de progressProperty .
Además de esto, quiero que un estado detallado sobre el elemento que se procesa se informe en la interfaz de usuario. Es decir, el nombre del archivo que se procesa junto con su tamaño y cualquier error que pueda surgir del proceso de un solo archivo.
La actualización de la interfaz de usuario con esta información no se puede hacer desde el subproceso de trabajo, como máximo puedo agregarla a una colección sincronizada.
Pero luego necesito algún evento para informar a la interfaz de usuario que hay nuevos datos disponibles.
¿Tiene javafx algún soporte específico para este problema?

actualización, mejor formulación

En lugar de diseñar un mecanismo de enlace cruzado ad hoc como Platform.runLater, estoy tratando de permitir que cada propiedad sea escuchada desde otros subprocesos. Al igual que runningProperty y stateProperty proporcionados por Task


Esta respuesta usa el mismo concepto que la respuesta de Daniel.

Se adjunta una copia de la muestra Resultado parcial del javadoc de Task (corregida para los errores de sintaxis actualmente incrustados en el javadoc de Java 8 y para agregar tipos genéricos más específicos). Puedes usar una modificación de eso.

Coloque sus excepciones en la colección partialResults. Para su caso, no necesita devolver la lista de excepciones de la Tarea, sino que puede CellFactory en algún control de la interfaz de usuario que muestra las excepciones (como un ListView con un CellFactory para la visualización de excepciones). Tenga en cuenta que la colección partialResults no tuvo que estar sincronizada porque siempre se actualiza y se accede a ella en el subproceso de la interfaz de usuario de JavaFX (la actualización se realiza a través de una llamada a Platform.runLater() similar a la solución de Daniel).

public class PartialResultsTask extends Task<ObservableList<Rectangle>> { private ReadOnlyObjectWrapper<ObservableList<Rectangle>> partialResults = new ReadOnlyObjectWrapper<>( this, "partialResults", FXCollections.observableArrayList( new ArrayList<>() ) ); public final ObservableList<Rectangle> getPartialResults() { return partialResults.get(); } public final ReadOnlyObjectProperty<ObservableList<Rectangle>> partialResultsProperty() { return partialResults.getReadOnlyProperty(); } @Override protected ObservableList<Rectangle> call() throws Exception { updateMessage("Creating Rectangles..."); for (int i = 0; i < 100; i++) { if (isCancelled()) break; final Rectangle r = new Rectangle(10, 10); r.setX(10 * i); Platform.runLater(() -> partialResults.get().add(r)); updateProgress(i, 100); } return partialResults.get(); } }

Al actualizar sus propiedades observables, la tarea primero verifica si la actualización se está produciendo en el hilo de la aplicación FX. Si lo es, hace una actualización inmediata. Si no lo es, envuelve la actualización en una llamada de Platform.runLater() . Consulte el código fuente de la tarea para entender cómo se hace esto.

Tal vez sería posible definir un conjunto de propiedades genéricas concurrentes, pero JavaFX no proporciona tales instalaciones en su núcleo. De hecho, no es necesario. Con la excepción del paquete javafx.concurrent, JavaFX es un marco de UI de un solo hilo.


Me estoy topando con un problema similar, por lo que puedo decir que usted tiene que lidiar con el manejo del error. Mi solución es actualizar la interfaz de usuario a través de una llamada de método:

Algo como:

try { //blah... } catch (Exception e) { reportAndLogException(e); } ... public void reportAndLogException(final Throwable t) { Platform.runLater(new Runnable() { @Override public void run() { //Update UI here } }); }

Esencialmente, simplemente lo estoy moviendo manualmente de nuevo al subproceso de la interfaz de usuario para una actualización (como lo haría en casi cualquier otro marco).