Search code examples
javajavafxjava.util.concurrent

Updating message in task hangs the application


I am using a background Thread to run my loading code and wish to bind the MessageProperty of the Task to a label.

However, when calling updateMessage() the task hangs; the message is never updated and the next line of code does not execute.

This is using JDK 1.10.1. Here is an MCVE:

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        VBox root = new VBox(10);
        Label label = new Label("Message");
        root.getChildren().add(label);

        primaryStage.setScene(new Scene(root));

        Task loadingTask = new LoadingTask();
        Thread loadingThread = new Thread(loadingTask);
        loadingThread.setDaemon(true);

        label.textProperty().bind(loadingTask.messageProperty());
        loadingThread.start();

        primaryStage.setWidth(200);
        primaryStage.setHeight(200);
        primaryStage.show();
    }
}

class LoadingTask<Void> extends Task {
    @Override
    protected Object call() throws Exception {
        System.out.println("Loading task ...");
        updateMessage("Loading task ...");
        System.out.println("Message: " + getMessage());

        return null;
    }
}

The output:

Loading task ...

The second System.out.println() is never executed.

Edit:

I added a simple GUI to my MCVE with a label bound to the MessageProperty. The label does get updated to show "Loading task ..." but the console output remains the same; code after the updateMessage() method is called does not execute.

2nd Edit:

I ran my step debugger, and an IllegalStateException is being thrown from the Task class: "Task must only be used from the FX Application Thread"

I'm not sure what that means as the whole point is to run this task on a different thread...


Solution

  • Your only issue is, that you must not access getMessage() from another thread than the FX UI-Thread. Try Platform.runLater(() -> System.out.println("Message: " + getMessage()));