by Richard Bair | Oct 14, 2011 | Architecture, FXML, Tips n' Tricks
JavaFX 2.0 shipped with a declarative XML-based language for defining user interfaces, called FXML. FXML is a key part of our strategy around making it easier to create user interfaces in Java. Certainly having a markup language has been attractive to web developers since it is a familiar and comfortable way to approach describing a user interface. But there are other key strategic reasons why FXML is important, how it fits into the broader JavaFX ecosystem, and how it helps you write testable user interfaces with minimal fuss. In essence, FXML helps you follow best practices while also making your life easier.
(more…)
by Richard Bair | Oct 6, 2011 | Uncategorized
I was just working my way through the last few days of posts on the JavaFX OTN forums and noticed somebody who was trying to learn how to write a custom layout pane and included the following code in the forum posting:
public class MyLayout extends Pane {
@Override protected void layoutChildren() {
// TODO
}
@Override protected void layoutInArea(Node arg0, double arg1, double arg2,
double arg3, double arg4, double arg5,
HPos arg6, VPos arg7) {
// TODO
}
@Override protected void impl_layoutBoundsChanged() {
// TODO
}
}
This reminded me that I had failed to write a blog warning of the perils of using impl_ methods in JavaFX 2.0. DON’T EVER USE THEM!!
(more…)
by Richard Bair | Oct 5, 2011 | Uncategorized
Whoa! It is kind of embarrassing that we haven’t yet blogged about the fact that JavaFX 2.0 has been released! In our defense, it has been a very busy past few days. At the JavaOne Technical keynote Monday morning I announced 4 things:
- GA Release of JavaFX 2.0 (32 bit XP, 32 & 64 bit Windows Vista and Windows 7)
- Developer Preview release of JavaFX 2.0 for Mac OS X
- Early Access (for partners) of JavaFX Scene Builder (RAD tool)
- Netbeans 7.1 Beta with support for JavaFX
In addition, on Tuesday Adam Messinger (VP Java SE, Java Client, Java ME — my bosses boss) announced that we are open sourcing all of JavaFX. We are asking the OpenJDK community for a new project where we will put JavaFX. In addition, we will be working with the JCP to propose JavaFX as an official standard part of the Java platform (probably targeted for Java 9).
There was also a very exciting demo which you probably have already seen, where Nandini Ramani (VP Java Client, my boss) showed JavaFX running on both a Samsung Galaxy Tab (atop Android) and an iPad. Needless to say, this has generated quite a bit of buzz. I’ll blog separately about how this works and why (I gave a session on the subject on Tuesday).
We’ll also be blogging with our slides from the conference. In the meantime, the conference is ongoing, and I’m late for a session I wanted to attend. I’ll also post some slides from the Monday Keynote and Tuesday keynote (if I can get my hands on them)
by Richard Bair | Jul 2, 2011 | API Design, General
For the past couple of years the industry has continued to follow Moore’s Law by shifting from CPU clock speed to increasing the number of cores and threads per core. Even cell phones are getting multiple cores these days! Taking advantage of all these cores and threads is one of the hallmarks of modern GUI platforms. But all this concurrency brings a multitude of problems to the application developer, not least of which is that writing multithreaded applications is hard!
In designing JavaFX 2.0, we of course needed to address both how the scene graph would behave in the presence of multiple threads, and how developers could effectively do work in background threads and keep the UI responsive. In short, the JavaFX scene graph, like all other mainstream GUI toolkits, is not thread-safe and must be accessed and manipulated from the UI thread (call the FX Application thread). Swing and AWT had the same basic policy (only work with Swing or AWT from the Event Dispatching Thread), as did SWT (only interact with SWT resources and components from the thread that owns them), as do all other major toolkits (JavaScript / HTML included).
The most common problem with this design is that developers who do not do work on background threads invariably create unresponsive applications, since this long lived (potentially blocking) code happens on the same thread that processes user events. That is, while your long lived operation is running, no mouse or key events are being processed, which leads to an application that appears to “hang”.
Further, actually writing well behaved background workers is difficult and error prone. Even if you create a Runnable and create a Thread and do your long-lived work in that background thread, at some point you need to communicate back to the UI, either with the result of the long-lived computation, or by communicating to a ProgressIndicator of some kind what the progress of this long-lived operation is. This is error prone, because you must be sure to communicate with the UI by putting events back onto the event queue (using Platform.runLater, the equivalent of Swing’s invokeLater).
Note: This article is a sneak peek at a new API which is coming in the next couple of weeks, but is not currently available in the Beta builds! There is a deprecated Task class in the beta builds which will be removed and replaced with the one detailed here.
Suppose we have a simple background thread which just counts from 0 to 1 million. Suppose I have a single ProgressBar, and that I need to update the progress of this ProgressBar as the counter runs. A naive implementation might look like this:
final ProgressBar bar = new ProgressBar();
new Thread(new Runnable() {
@Override public void run() {
for (int i=1; i<=1000000; i++) {
final int counter = i;
Platform.runLater(new Runnable() {
@Override public void run() {
bar.setProgress(counter/1000000.0);
}
});
}
}
}).start();
This is a hideous hunk of code, a crime against nature (and programming in general). First, you’ll lose brain cells just looking at this double nesting of Runnables. Second, it is going to swamp the event queue with little Runnables — a million of them in fact. Clearly, we needed some API to make it easier to write background workers which then communicate back with the UI.
Java comes with a very complete set of concurrency libraries in the java.util.concurrent package. We wanted to leverage what was already defined in Java, but we needed to extend these APIs to take into account the FX Application thread and the constraints that GUI programmers are under. The javafx.concurrent package contains three core files: Worker, Task, and Service.
Before diving into the rather verbose description (taken from the proposed javadocs) for Worker, Task, and Service I wanted to cut to the chase and show some examples. The first key thing to mention, is that Worker is an interface that is implemented by both Task and Service, and which adds the sort of convenience API necessary for a background worker that is useful for communicating back with a UI. Second, Task extends from java.util.concurrent.FutureTask. This means that a Task can very cleanly fit into the concurrent libraries. As you may know, FutureTask implements Runnable, and can be passed to an Executor’s execute() method.
So real quick, here is the same example as above, but it suffers from none of the flaws exhibited in the naive implementation.
Task task = new Task<Void>() {
@Override public Void run() {
static final int max = 1000000;
for (int i=1; i<=max; i++) {
updateProgress(i, max);
}
return null;
}
};
ProgressBar bar = new ProgressBar();
bar.progressProperty().bind(task.progressProperty());
new Thread(task).start();
In this example, I first create my Task. The task implementation just does its work, invoking the protected updateProgress
method defined on Task, which ends up updating progress, totalWork, and workDone properties on the Task. I then create my ProgressBar and bind its progress property with the progress property of the Task. Then, since Task is a Runnable, I can just create a new Thread passing it the Task and then start the Thread.
Alternatively, I could create an Executor or ExecutorService (such as a ThreadPoolExecutorService) and execute
the task using the ExecutorService.
(more…)