Wednesday, July 29, 2015

Java FX Event Thread vs AWT Event Thread Brawl

So, I recently started working on a Java UI application focussing on my backend first, then the UI components.  I am not very good at making pretty swing UIs (very out of practice - but I was really active when Swing was in development - what was that, 1997?  :| ).  I have done a lot have dynamic web development over the last decade and am frankly shocked that swing UIs are so far behind.  A dynamic swing UI to match a trivial web interface would be a LOT of work.  So, my first cut at my UI was targeted at behavior and testing, which was a substantial effort - I would have thought automated unit testing in the user interface would be in a better state than it is.

Almost every substantive UI testing platform appears to be abandoned (uispec4j, abbott, others I can't remember anymore) so I decided to build my own support as I needed it (Not building a generified UI unit testing framework - just what I needed).  The one good thing that came out of this approach was I realized testing the UI through the UI - as a user would or a record/playback testing method - was a big mistake.  I was decomposing my user interface as any good developer would do, but my testing was completely monolithic.  Instead, I started testing components at the finest grain and my tests became so much faster and easier to write with less bulk.  I also wired components together to rely on messages between objects rather than having handles to each other.  Sound familiar?  That should have been my approach from the start.

At any rate, I was going along, and decided it was time to make the user interface better, and I thought it might be time to look at Java FX.  One of the major factors was Oracle choosing FX as the future direction for java, but also the ease with which you can externalize the building of the user interface into fxml files.  That is huge.  I can use a builder and not be tied to a tool like eclipse or IntelliJ - big win.

I made a refactor which permitted me to transition from swing to Java FX as it seemed desirable, and even encouraged with the addition of JFXPanel.  This seemed ideal since rewriting the entire UI all at once sucks.  Well, this sucks worse.  The Java FX Event thread and AWT Event thread are entirely incompatible - so threading in the UI is a nightmare.  Consider as an example a Swing Button action handler which needs to update the state of an FX node - you would have to do that asynchronously, you can't call PlatformImpl.runAndWait from the AWT event thread - it will hang a lot of the time.  But if your button action handler needs to wait until the FX node is complete updating - such as if the update triggers another event handler - you have to do it all asynchronously with a lot of calls back and forth into the different event threads and you are left with a real mess.

To compensate - I have had to convert all messaging in the GUI to asynchronous - which makes unit testing a major hassle because obviously test code needs to wait until things are done before making assertions.  The bottom line to me is not to do this.  Transitioning to Java FX should be done at least at the Frame level - or Stage in Java FX parlance - and don't let messaging in the GUI depend on passing between the different systems.