While on vacation I’ve been watching twitter to see what kinds of things people are doing with JavaFX. One thing I’ve seen a fair amount of tweets on that is pretty gratifying is tying JavaFX to backend data services. One project is a port of Cairngorm from Flex to Java/JavaFX. Another was an earlier demo based on Hessian (which needs to be ported to JavaFX 1.2). Another was about integrating Flamingo to JavaFX.
It’s great to see a lot of people starting to play with this part of the JavaFX space because we haven’t really given much guidance to it yet. We do have some great web service APIs as a starting point (basic HTTP with HttpRequest, RSS and ATOM feed support), but haven’t so far given any guidance as to writing an end to end app. I wanted to take just a moment and outline how we designed the Task API and how it ought to be used by third parties when creating background tasks or services, including communicating with a server.
I also wanted to give a shout out to an excellent blog by my colleague Baechul who has been writing some very detailed and well written articles on JavaFX. Of particular interest to this post is one he wrote on JavaFX 1.2 Async.
The Task class in the javafx.async represents the basic programming model for all asynchronous tasks in JavaFX and should form the base class for all such background Tasks. Its design was heavily influenced by the excellent work of Hans Muller on the Swing Application Framework. All JavaFX Tasks have the notion of “state” and “progress”. The state of the Task is expressed though a series of public API members:
- started:Boolean
- stopped:Boolean
- failed:Boolean
- succeeded:Boolean
- done:Boolean
We chose to break these states out into Boolean properties rather than have a single property with an enum for two reasons. First, it makes it a little cleaner in the onDone event handler to find out what state the Task ended up in, especially when checking for several states. Second, this allows you to bind to the state of the Task from an external class using some rather clean code. For example, suppose you had a progress indicator and error icon and wanted to make it so that if the task failed, the error icon would be made visible, otherwise the progress indicator would be visible and display progress appropriately.
Group { content: [ ProgressIndicator { visible: bind task.started and not task.failed and not task.stopped progress: bind task.percentDone } ErrorIndicator { // this class doesn't exist, but you could write a CustomNode visible: bind task.started and task.failed causeOfFailure: bind task.causeOfFailure } ] }
You’ll notice in this code block I’m also taking advantage of another really nice feature of Task and ProgressIndicator. A ProgressIndicator has a progress
property which, if -1, means it is indeterminate but if between 0 and 1 then it indicates the percent done. Task also has a similar property called percentDone
where, if -1, it means that the progress of the Task is also indeterminate. This makes binding a ProgressIndicator to a Task very clean. Simply bind like this: ProgressIndicator { progress: bind task.percentDone }
and the rest works exactly like it should (switching between determinate and indeterminate mode automatically).
There are several API members for tasks for tracking progress:
- progress
- maxProgress
- percentDone
To help explain these properties lets imagine that our Task was to read a file from disk. In this case, progress
could be used to indicate the number of bytes read from disk. maxProgress
would indicate the size of the file in bytes, and percentDone
would be automatically calculated based on progress
and maxProgress
. In this way, you can create a UI which will track not only the percent done, but also the discrete amount of work to be done, and how much has been done.
Another simple example would be computing prime numbers. Suppose your app wanted to compute the first 5 prime numbers. In this case, maxProgress
would be 5, and progress
would be incremented each time a prime number is computed.
Finally, there are two event handlers that all Tasks share: onStart
and onDone
. onStart
is called whenever the Task’s start()
method is called, not when the background task is actually started. For example, your Task implementation might push work onto a worker queue. In this case, onStart
should be called immediately after start()
is invoked, not when the actual background worker that was pushed on the queue starts working.
The onDone
function is called whenever the task stops, for any reason. If the task was cancelled manually, or if there was a failure, or if the task completed successfully. In all these cases onDone will be called. I’d like to add “onSuccess” and “onFailure” and “onStopped” events in the future. It is the developer’s responsibility in onDone to check the state of the Task to determine whether the task succeeded or failed or was stopped by checking the state booleans of the Task.
All background operations in JavaFX should extend from Task. This design gives application developers a single common programming model to use with all background operations developed by the JavaFX team or by third party developers. HttpRequest was refactored to be a Task in 1.2 (hence the reason for some of the API changes between 1.1 and 1.2).
There is one major caveat that I need to make clear. As of JavaFX 1.2, JavaFX Script is single threaded. All background work must be done in Java code. The JavaTaskBase
abstract class is the base class intended to be used by all background threading implementations in JavaFX 1.2. Unfortunately, the hookup between JavaTaskBase
and RunnableFuture
didn’t come out right in 1.2 and you’re left with very little guidance as to how to do this appropriately.
The key thing is to understand that nothing should touch JavaFX variables from a background thread. So the idiom to use is to have the JavaTaskBase subclass to have a Java language peer which does the background work. The JavaTaskBase subclass would register a listener on the peer, and the peer would communicate back to the JavaTaskBase through that listener interface. The JavaTaskBase subclass would then pump events from the peer back onto the JavaFX thread (i.e. event thread) using FX.deferAction.
That’s a whole other blog entry though. For starters, I suggest reading Baechul’s take on it.
There is one last thing I wanted to mention, which is a futures item which Brian Goetz and I have been bouncing around a bit. It’s completely pie-in-the-sky at this point, take it with a grain of salt, etc etc. Having to write background tasks in Java is a pain at the moment primarily because you cannot create JavaFX objects in a background thread. Also, it involves writing a messaging interface, a Java class, and a JavaTaskBase subclass. What I’d like to see is something like this:
var task = BackgroundTask { run: function() { // code in this function runs in a background thread defer(function() { // code in this function runs on the JavaFX thread }); } }
The kicker is, the compiler would check and enforce that you don’t illegally modify application state from the background thread, but that you can when using “defer” or “deferAction”. The thing that gets me all excited about the idea is that we don’t have to expose a full threading model (with synchronicity, concurrent collections, memory barriers, semaphores, or anything else), but can instead simplify the problem by having a much more limited coarse grained approach of “this body of work happens in some background thread”. If you want or need to have a full threading model, then we still make that available by writing a JavaTaskBase subclass, but for the vast majority of uses, you could just use the simplified BackgroundTask model.
Excellent post.
Threading is an important benefit you get with JavaFX over other technologies in this space, and it works in a fairly easy to use way.
I found creating the asynchronous RMI service for Cairngorm-FX pretty straightforward in the end.
One thing that I found a little annoying is that there is a lot of information that is outdated on the web, so the more articles on these new API’s is great.
@Jethro, thanks. If you have any good links to a short & sweet summary of Cairngorm (especially how to use the FX version), let me know. I’d be interested in reading up on it more.
What you outline at the end of this post sounds very exciting – I’d certainly like to see something like this to make background threading easier.
Keep up the good work 🙂
— Jonathan Giles
Its great to see that JavaFX now has a solution. In 1.0/1.1 days of JavaFX – I had to use SwingWorker and all the Swing Components to have components in UI in insync with whats happening in SwingWorker
Didn’t the original F3 have something similar to the threading model you describe at the end? What was wrong with that?
F3 was playing with these same ideas but didn’t end up in the same place I’d like to see it go. One thing that was nice about F3 was it had special language support for declaring the background thread instead of having to create an API class as I’ve proposed above. I hope we also get to that point.
F3 had two constructs:
do { … }
do later { … }
If you read the F3 language resource (http://blogs.sun.com/chrisoliver/resource/f3.html) you’ll see that Chris didn’t think that “do” was quite right. And in fact, I’m not sure its terribly useful. Even in Swing I’ve hardly ever used do as opposed to do later.
I believe that “do later” in fact is also different from what I’ve proposed above because the body of the “do later” actually runs on an EDT — just at some later time. So this is the same as FX.deferAction in the current SDK. I’m not an expert on F3 though, so I could be wrong.
Also, notice this comment in the above mentioned document:
“Such code must only access Java objects (and those objects must handle their own thread synchronization, if necessary)”
So in F3 you still couldn’t access or create F3 objects in a background thread. In the approach I’m proposing, you can in fact create JavaFX objects off thread, but the compiler will make sure you don’t interact incorrectly with objects declared elsewhere.
Also, in F3 there wasn’t a full “Task” like API that backed the operation, so you couldn’t bind up to progress or other such things
I received a report today that with JavaFX 1.2, Task is returning percentDone as a value between 0 and 100 rather than the correct answer which is between 0 and 1. I have filed an issue and will see that if this is the case then it will be fixed in the next release. This is considered a critical bug.
I would like to know much about how JavaFX supports on current mobile devices only running JVM, As I read, It needs a FX runtime on top of JVM to run these applications. Thanks
I would like to know much about how JavaFX supports on current mobile devices only running JVM, As I read, It needs a FX runtime on top of JVM to run these applications. Thanks
The thing you’re talking about last would be an excellent addition! The most practical annoying thing I run into now is that there is no way to parse xml in the background. This means the UI freezes for a second as soon as a HTTP request returns and parsing starts.