invokeAndWait for JavaFX

Swing offers the two methods SwingUtilities.invokeAndWait(…) and SwingUtilities.invokeLater(…) to execute a Runnable object on Swings event dispatching thread. You can read more about this methods here.

As I currently know JavaFX provides only Platform.runLater(…) that is the equivalent of SwingUtilities.invokeLater(…). A “runAndWait” method doesn’t exist at the moment. While developing some DataFX stuff and my first Raspberry Pi demo I needed this feature in JavaFX. So I created a runAndWait method that will hopefully be part of DataFX in some future. Until then you can use this code in your project:

import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import javafx.application.Platform;

/**
 * General JavaFX utilities
 * 
 * @author hendrikebbers
 * 
 */
public class FXUtilities {

	/**
	 * Simple helper class.
	 * 
	 * @author hendrikebbers
	 * 
	 */
	private static class ThrowableWrapper {
		Throwable t;
	}

	/**
	 * Invokes a Runnable in JFX Thread and waits while it's finished. Like
	 * SwingUtilities.invokeAndWait does for EDT.
	 * 
	 * @param run
	 *            The Runnable that has to be called on JFX thread.
	 * @throws InterruptedException
	 *             f the execution is interrupted.
	 * @throws ExecutionException
	 *             If a exception is occurred in the run method of the Runnable
	 */
	public static void runAndWait(final Runnable run)
			throws InterruptedException, ExecutionException {
		if (Platform.isFxApplicationThread()) {
			try {
				run.run();
			} catch (Exception e) {
				throw new ExecutionException(e);
			}
		} else {
			final Lock lock = new ReentrantLock();
			final Condition condition = lock.newCondition();
			final ThrowableWrapper throwableWrapper = new ThrowableWrapper();
			lock.lock();
			try {
				Platform.runLater(new Runnable() {

					@Override
					public void run() {
						lock.lock();
						try {
							run.run();
						} catch (Throwable e) {
							throwableWrapper.t = e;
						} finally {
							try {
								condition.signal();
							} finally {
								lock.unlock();
							}
						}
					}
				});
				condition.await();
				if (throwableWrapper.t != null) {
					throw new ExecutionException(throwableWrapper.t);
				}
			} finally {
				lock.unlock();
			}
		}
	}
}

It’s working for all my needs. Please give me some feedback if there are any problems or bug.

8 Responses to invokeAndWait for JavaFX

  1. Hi Hendrik,
    nice solution! You should be aware of condition.wait() and change it to while(!myCondition) condition.wait() otherwise a condition.signalAll() from user code can create strange behavior. I also add some while(!myCondition && Application.isActive()) condition.await() to my code because it can happen the a Platform.exit() will destroy the JavaFX application thread and the calling thread will wait for ever.
    Otherwise… nice work

    Thank you

    Andy

  2. This will also do the trick (for Runnable and Callable):


    private void runAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
    FutureTask future = new FutureTask(runnable, null);
    Platform.runLater(future);
    future.get();
    }

    private T runAndWait(Callable callable) throws InterruptedException, ExecutionException {
    FutureTask future = new FutureTask(callable);
    Platform.runLater(future);
    return future.get();
    }

    Cheers,
    Tom

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>