62

I have an application that has a TableView that has an attached listener so it refreshes as soon as it detects a change, but the thing is that I´m getting java.lang.IllegalStateException: Not on FX application thread; currentThread = Smack Listener Processor (0). Here is my code:

/**
 * This function resets the pagination pagecount
 */
public void resetPage() {
    try {
        System.out.println("RESET"); 
        int tamRoster = this.loginManager.getRosterService().getRosterList().size();
        paginationContactos.setPageCount((int)(Math.ceil(tamRoster*1.0/limit.get())));
        int tamEnviados = this.loginManager.getRosterService().getEnviadasList().size();
        paginationEnviadas.setPageCount((int)(Math.ceil(tamEnviados*1.0/limit.get())));
        int tamRecibidas = this.loginManager.getRosterService().getRecibidasList().size();
        paginationRecibidas.setPageCount((int)(Math.ceil(tamRecibidas*1.0/limit.get())));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void doSomething () {
        this.loginManager.getRosterService().getRosterList().addListener(new ListChangeListener<RosterDTO>() {
            @Override
            public void onChanged(
                    javafx.collections.ListChangeListener.Change<? extends RosterDTO> c) {
                // TODO Auto-generated method stub
                resetPage();
                while (c.next()) {
                    if (c.wasPermutated()) {
                        System.out.println("PERM");
                    } else if (c.wasUpdated()) {
                        System.out.println("UPD");
                    } else {
                        System.out.println("ELSE");
                    }
                }
            }
         });
}

Altough it enters the resetPage method, I get that exception. Why is this happening? How can I fix it?

starball
  • 20,030
  • 7
  • 43
  • 238
linker85
  • 1,601
  • 5
  • 26
  • 44

3 Answers3

139

The user interface cannot be directly updated from a non-application thread. Instead, use Platform.runLater(), with the logic inside the Runnable object. For example:

Platform.runLater(new Runnable() {
    @Override
    public void run() {
        // Update UI here.
    }
});

As a lambda expression:

// Avoid throwing IllegalStateException by running from a non-JavaFX thread.
Platform.runLater(
  () -> {
    // Update UI here.
  }
);
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Marc
  • 2,631
  • 1
  • 12
  • 13
  • 2
    Where do you place this code? I Try to do it when I instantiate my Stage and set the stage, but then I dont get the error, but the page comes back blank. – Travis Tubbs Sep 24 '18 at 16:22
4

JavaFX code allows updating the UI from an JavaFX application thread. But from the above exception message it says that it is not using FX Application thread.

One way you can fix is to launch an FX Application thread from the resetPage method and do the modifications there.

MohamedSanaulla
  • 6,112
  • 5
  • 28
  • 45
0

I had a similar issue which I fixed without using the Platform.runLater():

"java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-6"

Button play = new Button("Play");
EventHandler<ActionEvent> playHandler = e1 -> {
    Runnable runnable = () -> {

        play.setText("Pause");

        EventHandler<ActionEvent> timelineHandler e2 -> play();
        timeline = new Timeline(new KeyFrame(Duration.millis(2000), timelineHandler));
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.play();

    };
    Thread t = new Thread(runnable);
    t.start();
};
play.setOnAction(playHandler);

SOLVED! Move everything unrelated outside of the runnable lambda:

Button play = new Button("Play");
EventHandler<ActionEvent> playHandler = e1 -> {
    play.setText("Pause");
    Runnable runnable = () -> {

        EventHandler<ActionEvent> timelineHandler e2 -> play();
        timeline = new Timeline(new KeyFrame(Duration.millis(2000), timelineHandler));
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.play();

    };
    Thread t = new Thread(runnable);
    t.start();
};
play.setOnAction(playHandler);
  • I know this is just a snippet, but this code looks like bad coding to me. – SedJ601 May 15 '22 at 16:41
  • yeah for sure ! – Luke Palmer May 18 '22 at 19:48
  • To be clearer on my part. Why are you using a `Thread` to start a `Timeline`? Why do you have an `ActionEvent` inside an `ActionEvent`? Why are you calling `e2 -> play();` and `timeline.play()`. Like I said, I know this is just a snippet, but some of this code makes no sense. This question appears to be a situation created by bad code. – SedJ601 May 18 '22 at 23:27