2

My application adds multiple Runnable on FX thread, by calling Platform.runlater method, then, I want to do some calculations only when there is no additional Runnable is in the FX Platform queue. But I don't know the right way, is there any event or callback mechanism to get the right time?
Currently I force the application thread to sleep randomly MILLISECONDS.

Puce
  • 37,247
  • 13
  • 80
  • 152
Reza Afzalan
  • 5,646
  • 3
  • 26
  • 44
  • I'm not sure what you're trying to achieve. Does your whole processing start from a backround thread? Platform.runlater will run code on the JavaFX Application Thread along with any GUI events. I don't think you can control GUI events except to explicitly freeze the UI... – Puce Sep 23 '16 at 08:10
  • Some more description will be appreciated(what you want to do).Why you will have to wait JavaFX to finish rendering before you do the calculations?How the Random Thread Sleep was solving the problem? – GOXR3PLUS Sep 23 '16 at 08:11
  • If you can reverse the process and start from the JavaFX Application Thread you can use the utility classes in http://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/package-summary.html to run code in a background thread. – Puce Sep 23 '16 at 08:13
  • 1
    "when there is no additional `Runnable` in the FX Platform queue" - this may never happen. You don't know what other code is submitting to that queue, and you don't know how they are being processed from it. What do you really want to do? If you want to block your background thread until the `Runnable` is complete, you can submit a `FutureTask` instead of a `Runnable`, then call `FutureTask.get()` which will block until that task has completed. – James_D Sep 23 '16 at 12:04
  • @Puce , Currently I'm testing JavaFX gui using TestFX package, testing is done by extending GuiTest class. – Reza Afzalan Sep 23 '16 at 13:02
  • @GoXR3Plus random sleep in test thread let javafx thread finish runables, before next step. – Reza Afzalan Sep 23 '16 at 13:05

1 Answers1

4

This is a bad idea from the start since you do not know what other code uses Platform.runLater. Also you should not rely on such implementation details; for all you know the queue could never be empty.
However you could post those Runnables using a custom class that keeps track of the number of Runnables and notifies you when all are done:

public class UpdateHandler {
     private final AtomicInteger count;
     private final Runnable completionHandler;

     public UpdateHandler(Runnable completionHandler, Runnable... initialTasks) {
         if (completionHandler == null || Stream.of(initialTasks).anyMatch(Objects::isNull)) {
             throw new IllegalArgumentException();
         }
         count = new AtomicInteger(initialTasks.length);
         this.completionHandler = completionHandler;
         for (Runnable r : initialTasks) {
             startTask(r);
         }
     }

     private void startTask(Runnable runnable) {
         Platform.runLater(() -> {
             runnable.run();
             if (count.decrementAndGet() == 0) {
                 completionHandler.run();
             }
         });
     }

     public void Runnable runLater(Runnable runnable) {
         if (runnable == null) {
             throw new IllegalArgumentException();
         }
         count.incrementAndGet();
         startTask(runnable);
     }

}
fabian
  • 80,457
  • 12
  • 86
  • 114