hilos - runlater javafx
Tarea concurrente para actualizar el objeto complejo JavaFX-¿equivalente al swingworker? (1)
Quiero ejecutar una tarea en segundo plano actualizando los resultados intermedios en la vista. Estoy tratando de implementar la aplicación MVC JavaFX. La tarea se define en el Modelo. Deseo enviar los resultados parciales principales de la amenaza para mostrarlos en la Vista. Yo uso updateValue () para hacerlo. Además, defino la propiedad del objeto y un oyente en el controlador.
Mi problema: el método cambiado () del oyente no se activa cada vez que se ejecuta updateValue () en la Tarea. ¿Por qué? ¿Cómo puedo obligarlo a hacer esto?
No he encontrado muchos ejemplos complejos.
Lo que tengo hasta ahora
Model.cpp
ComplexObject _complexO;
public Task<ComplexObject> getModelTask() {
return new Task<ComplexObject>() {
@Override
protected ComplexObject call() throws Exception {
int numberOfFiles = 0;
boolean filesToRead = true;
while (filesToRead){
// ....
_complexO = new ComplexObject();
try{
//..
if(f.exists()){
_complexO.initialize();
numberOfScans ++;
}
else{
_complexO.initializeToNull();
}
String stringNumber = Converter.toString(numberOfFiles);
updateMessage(stringNumber);
updateValue(_complexO );
} catch(Exception ex){
ex.printStackTrace();
_complexO = null;
return _complexO;
}
filesToRead = areThereFilesToRead();
}
return _complexO;
}
};
}
Controller.cpp
...
Task< ComplexObject> task = _model.getModelTask();
_AJavaFXTextField.textProperty().bind(task.messageProperty());
_AJavaFXTextField.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue observable, String oldValue, String newValue) {
System.out.println("Success with messageProperty!!" + newValue);
}
});
SimpleObjectProperty<ComplexObject> complexObjectProperty = new SimpleObjectProperty<>();
complexObjectProperty.bind(task.valueProperty());
complexObjectProperty.addListener(new ChangeListener<ComplexObject>(){
@Override
public void changed(ObservableValue<? extends ComplexObject> observable, ComplexObject oldValue, ComplexObject newValue) {
if(newValue.data == null ) {
System.out.println("value is new!!! " + scansNumber);
}
else if(newValue.isValid()){
System.out.println("I want to plot newValue data here");
}
}
});
Thread th= new Thread(task);
System.out.println("call TASK");
th.start();
}
Mis preguntas / conclusiones aquí:
Cómo forzar todo el tiempo que ejecuto en la tarea updateValue () para ejecutar realmente el oyente, así que ejecute el código donde quiero trazar los datos.
¿Por qué es más veces disparar el enlace para la propiedad messageProperty que valueProperty? - debería ser el mismo número de veces.
¿Por qué me parece que el código del oyente se dispara más veces cuando el modo de depuración que la ejecución normal?
Cualquier recomendación de buenas fuentes sobre este tema (desde un punto de vista complejo) sería genial.
Estoy buscando algo en JavaFX para reemplazar SwingWorker.
Lo que realmente quiero al final: devolver una lista de objetos complejos de la tarea, e idealmente, updateValue () enviaría los objetos uno por uno (resultados parciales)
Lo he seguido: https://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html
Muchas gracias por cualquier contribucción
Task
solo garantiza que un valor pasa a updateValue
o un valor pasado más tarde se establecerá en la propiedad del value
. Esto se hace para aumentar el rendimiento del subproceso de la aplicación al limitar el número de cambios que se les notifica a los oyentes.
¿Por qué es más veces disparar el enlace para la
valueProperty
messageProperty
quevalueProperty
? - debería ser el mismo número de veces.
Como se describió anteriormente, simplemente no hay garantía sobre el número de actualizaciones.
¿Por qué me parece que el código del oyente se activa más veces cuando el modo de depuración que la ejecución normal?
En general, la depuración hace que su programa sea más pequeño. Cuanto menor sea la frecuencia de actualización del hilo de la Task
, menor será el número de actualizaciones entre las veces que la clase Task
actualice las propiedades y menor el número de omisiones. (Las actualizaciones probablemente se ejecuten en cada cuadro o cada pocos cuadros). Si incluso utiliza un punto de inflexión / paso a paso en la tarea, probablemente haga que la Task
extremadamente lenta mientras el hilo de la aplicación se ejecuta a velocidad normal.
Debería ser fácil implementar la publish
por su cuenta utilizando una List
para almacenar las actualizaciones
public abstract class JavaFXWorker<S, T> extends Task<S> {
private List<T> chunks = new ArrayList<>();
private final Object lock = new Object();
private boolean chunkUpdating = false;
protected final void publish(T... results) {
synchronized (lock) {
chunks.addAll(Arrays.asList(results));
if (!chunkUpdating) {
chunkUpdating = true;
Platform.runLater(() -> {
List<T> cs;
synchronized (lock) {
cs = chunks;
// create new list to not unnecessary lock worker thread
chunks = new ArrayList<>();
chunkUpdating = false;
}
try {
process(cs);
} catch (RuntimeException ex) {
}
});
}
}
}
protected void process(List<T> chunks) {
}
}
Uso de muestra
@Override
public void start(Stage primaryStage) {
ListView<Integer> lv = new ListView<>();
Button btn = new Button("Run");
btn.setOnAction((ActionEvent event) -> {
JavaFXWorker<Void, Integer> worker = new JavaFXWorker<Void, Integer>() {
@Override
protected Void call() throws Exception {
final int maxCount = 100;
Random random = new Random();
int breakIndex = random.nextInt(maxCount-1)+1;
for (int i = 0; i < breakIndex; i++) {
publish(i);
}
// some break simulating a part long part of the task with no updates
Thread.sleep(3000);
for (int i = breakIndex; i <= maxCount; i++) {
publish(i);
}
return null;
}
@Override
protected void process(List<Integer> chunks) {
lv.getItems().addAll(chunks);
}
};
new Thread(worker).start();
});
Scene scene = new Scene(new VBox(btn, lv));
primaryStage.setScene(scene);
primaryStage.show();
}