SlideShare a Scribd company logo
Know them, or you will get angry.
JavaFX Pitfalls
CON4789
Warning
This presentation contains
a heavy load of code
Speaker
@sialcasa
Alexander Casall
Software Architect & Scrum Product Owner
Custom Software Development Company in Germany
Dresden, Munich, Berlin, Hamburg, Leipzig…
225 employees
3 Scrum Teams in JavaFX Projects
±7 consultants supporting JavaFX projects on customer side
alexander.casall@saxsys.de
Speaker
Andy Moncsek
Senior Consultant Application Development
Trivadis AG Switzerland - Zürich
600 employees in Switzerland, Germany and Austria
consulting, development, BI, infrastructure, operation
andy.moncsek@trivadis.com
@andyahcp
FXML / Caching
Memory
Threading and Services
Pixel Operations
Examples
https://github.com/sialcasa/javafx-pitfalls
Before we start:
If you are looking for common performance tipps regarding JavaFX
https://wiki.openjdk.java.net/display/OpenJFX/Performance+Tips+and+Tricks
FXML / Caching
FXML-Loading Performance
FXML / Caching
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.chart.*?>
<?import javafx.scene.shape.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40">
<children>
<BorderPane prefHeight="200.0" prefWidth="200.0">
<center>
<SplitPane dividerPositions="0.29797979797979796" prefHeight="160.0" prefWidth="200.0" Bord
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<TabPane layoutX="-32.0" layoutY="-31.0" prefHeight="200.0" prefWidth="200.0" t
<tabs>
<Tab text="Untitled Tab 1">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth
<children>
<TextFlow layoutX="-86.0" layoutY="-30.0" prefHeight="200.0"
<children>
<TitledPane animated="false" text="untitled">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeig
<children>
DEMO
Conclusion
wildcard imports are bad - check your FXML files
IntelliJ IDEA has import optimisation
We’ll fix this issue on Scene Builder
Why you don’t use caching?
FXML / Caching
What caching does
extends	
  Node
myMagicalCircle.setCache(true);
Image
Why should you use it?
magical circles are expensive to render
GPU
The movement of the element causes rendering effort
GPU
GPU
Other nodes can also cause rendering
Caching avoids unnecessary rendering of nodes
Why should you use it?
GPU
myMagicalCircle.setCache(true)
no more rendering caused e.g. by movement or overlapping nodes
Demo
Conclusion
simple objects which change often
complex objects which don’t change
(Don’t) cache…
Memory
Listener can cause memory leaks
Memory
public class TemporaryView extends StackPane {
public TemporaryView(Car dataModel) {
dataModel.name.addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable,
String oldValue, String newValue) {
//Do Something
}
});
}
}
public class Car {
StringProperty name = new SimpleStringProperty("Audi");
}
Instances of anonymous inner
classes hold on to a reference
to their enclosing instances
even if these references are
never actually used.
references
@Override
public void start(Stage primaryStage) throws Exception {
this.longlivingData = new Car();
this.root = new VBox(new TemporaryView(longlivingData));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
} VBox in Stage
Temporary
View
long living
Data Model
root.getChildren().clear();
Application Lifetime
VBox in Stage
Temporary
View
long living
Data Model
Temporary
View
Application Lifetime
VBox in Stage
Temporary
View
long living
Data Model
Temporary
View
retains in memory
omg, it’s a leak
How to avoid it?
Use WeakListener (dangerous)
Do manual Housekeeping
Demo
Conclusion
Listeners can leak
WeakListeners are dangerous
manage your Listeners manually
avoid anonymous implementations
Be aware of lost listeners!
Memory
DoubleProperty one=…;
DoubleProperty two=…;
this.one.add(this.two).
addListener((x, y, z) -> {
if (z != null && z.intValue() == 10) {
Alert alert = new Alert(…);
alert.showAndWait();
}
});
The listener get’s garbage collected
Same as:
DoubleProperty one=…;
DoubleProperty two=…;
NumberBinding add = Bindings.add(one, two);
add.addListener((x, y, z) -> {
if (z != null && z.intValue() == 10) {
Alert alert = new Alert(…);
alert.showAndWait();
}
});
The listener get’s garbage collected
DEMO
Conclusion - reference the binding
DoubleProperty one=…;
DoubleProperty two=…;
this.add = Bindings.add(one, two);
this.add.addListener((x, y, z) -> {
if (z != null && z.intValue() == 10) {
Alert alert = new Alert(…);
alert.showAndWait();
}
});
Threading and Services
It’s hard to test JavaFX Services!
Threading and Services
public class TestService extends Service<String> {
@Override
protected Task<String> createTask() {
return new Task<String>() {
@Override
protected String call() throws Exception {
Thread.sleep(5000);
return "I'm an expensive result.";
}
};
}
}
How to test this?
Not FX specific:
How to test async behaviour?
@Test
public void testLongLastingOperation() throws … {
TestService service = new TestService();
CompletableFuture<String> future = new CompletableFuture<>();
service.valueProperty().addListener((b, o, n) -> {
if (n != null) {
future.complete(n);
}
});
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
}
Green or Red?
java.lang.IllegalStateException:	
  Toolkit	
  not	
  initialized	
  
	
   at	
  com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:
	
   at	
  com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:
	
   at	
  javafx.application.Platform.runLater(Platform.java:83)	
  
	
   at	
  javafx.concurrent.Service.runLater(Service.java:913)	
  
	
   at	
  javafx.concurrent.Service.start(Service.java:676)	
  
…	
  
@Test
public void testLongLastingOperation() throws … {
TestService service = new TestService();
CompletableFuture<String> future = new CompletableFuture<>();
service.valueProperty().addListener((b, o, n) -> {
if (n != null) {
future.complete(n);
}
});
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
}
Green or Red?
Needs started FX-Toolkit
Ok… let’s fix this
@RunWith(JfxRunner.class)
public class ServiceNotTestableTest {
@Test
public void testLongLastingOperation() throws … {
TestService service = new TestService();
CompletableFuture<String> future = new CompletableFuture<>();
service.valueProperty().addListener((b, o, n) -> {
if (n != null) {
future.complete(n);
}
});
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
}
<dependency>
<groupId>de.saxsys</groupId>
<artifactId>jfx-testrunner</artifactId>
<version>1.2-SNAPSHOT</version>
</dependency>
But…
The Service has the intention
to be reused multiple times.
Let’s test this!
Let’s do a small refactoring
@RunWith(JfxRunner.class)
public class TestableServiceTest {
@Test
public void testLongLastingOperation() throws … {
TestService service = new TestService();
CompletableFuture<String> future = new CompletableFuture<>();
service.valueProperty().addListener((b, o, n) -> {
if (n != null) {
future.complete(n);
}
});
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
}
@RunWith(JfxRunner.class)
public class TestableServiceTest {
@Test
public void testLongLastingOperation() throws … {
TestService service = new TestService();
//refactored the Completable future stuff with the listeners in a method
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
}
}
@RunWith(JfxRunner.class)
public class TestableServiceTest {
@Test
public void testLongLastingOperation() throws … {
TestService service = new TestService();
//refactored the Completable future stuff with the listeners in a method
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
}
}
Green or Red?
java.lang.IllegalStateException:	
  Service	
  must	
  
only	
  be	
  used	
  from	
  the	
  FX	
  Application	
  Thread	
  
	
   at	
  javafx.concurrent.Service.checkThread(Service.java:906)	
  
	
   at	
  javafx.concurrent.Service.valueProperty(Service.java:205)	
  
	
   at	
  
de.saxsys.pitfalls.services.ClassToTestTest.testLongLastingOperation(ClassToTestTest.java:
40)	
  
	
   at	
  sun.reflect.NativeMethodAccessorImpl.invoke0(Native	
  Method)	
  
	
   at	
  sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)	
  
	
   at	
  sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:	
  
@RunWith(JfxRunner.class)
public class TestableServiceTest {
@Test
public void testLongLastingOperation() throws … {
TestService service = new TestService();
//refactored the Completable future stuff with the listeners in a method
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
}
}
Exception goes here
Let’s have a look on the Service Implementation
@Override public final V getValue() { checkThread(); return value.get(); }
@Override public final ReadOnlyObjectProperty<V> valueProperty() { checkThread(); return value;}
/**
* Cancels any currently running Task, if any, and restarts this Service. The state
* will be reset to READY prior to execution. This method should only be called on
* the FX application thread.
*/
public void restart() {
checkThread();
…
}
void checkThread() {
if (startedOnce && !isFxApplicationThread()) {
throw new IllegalStateException("Service must only be
used from the FX Application Thread");
}
}
first restart()
second restart()
But I wan’t to call my service multiple times
in my test - because this is it’s use-case.
Let’s test this in the FX-
Thread
@RunWith(JfxRunner.class)
public class TestableServiceTest {
@Test
public void testLongLastingOperation() throws … {
TestService service = new TestService();
//refactored the Completable future stuff with the listeners in a method
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
}
}
@RunWith(JfxRunner.class)
public class TestableServiceTest {
@Test
@TestInJfxThread
public void testLongLastingOperation() throws … {
TestService service = new TestService();
//refactored the Completable future stuff with the listeners in a method
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
}
}
jfx-testrunner annotation
@RunWith(JfxRunner.class)
public class TestableServiceTest {
@Test
@TestInJfxThread
public void testLongLastingOperation() throws … {
TestService service = new TestService();
//refactored the Completable future stuff with the listeners in a method
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
}
}
Green or Red?
java.util.concurrent.TimeoutException
at java.util.concurrent.CompletableFuture.timedGet(CompletableFuture.java:1763)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1907)
at de.saxsys.pitfalls.services.nottestable.ServiceNotTestableTest.testLongLastingOperationInFXThread(
TestServiceTest.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at de.saxsys.javafx.test.JfxRunner.access$0(JfxRunner.java:1)
at de.saxsys.javafx.test.JfxRunner.lambda$0(JfxRunner.java:47)
at de.saxsys.javafx.test.JfxRunner$$Lambda$56/1865127310.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$170(PlatformImpl.java:295)
at com.sun.javafx.application.PlatformImpl$$Lambda$52/1724593206.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$171(PlatformImpl.java:294)
at com.sun.javafx.application.PlatformImpl$$Lambda$51/580016451.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
@RunWith(JfxRunner.class)
public class TestableServiceTest {
@Test
@TestInJfxThread
public void testLongLastingOperation() throws … {
TestService service = new TestService();
//refactored the Completable future stuff with the listeners in a method
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
CompletableFuture<String> future = createFutureWithListener(service);
service.restart();
assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS));
}
}
Line 85: .get()
blocks the UI Thread
Ok, correct solution:
start with Test Thread and move all Service accesses to FX Thread
FX Thread
@Test
public void testLongLastingOperationSimple() throws … {
TestService service = new TestService();
CompletableFuture<String> future = new CompletableFuture<>();
Platform.runLater(() -> {
service.valueProperty().addListener((b, o, n) -> {
if (n != null) {
future.complete(n);
}
});
service.restart();
});
assertEquals("I'm an expensive result. 1", future.get(5, TimeUnit.SECONDS));
}
Ok, let’s run and test the Service
multiple times
@Test
public void testLongLastingOperationSimple() throws … {
TestService service = new TestService();
CompletableFuture<String> future = new CompletableFuture<>();
Platform.runLater(() -> {
service.valueProperty().addListener((b, o, n) -> {
if (n != null) {
future.complete(n);
}
});
service.restart();
});
assertEquals("I'm an expensive result. 1", future.get(5, TimeUnit.SECONDS));
CompletableFuture<String> future = new CompletableFuture<>();
Platform.runLater(() -> {
service.valueProperty().addListener((b, o, n) -> {
if (n != null) {
future.complete(n);
}
});
service.restart();
});
assertEquals("I'm an expensive result. 1", future.get(5, TimeUnit.SECONDS));
}
For each execution of the Service you have to double the
amount of the (boilerplate)-code.
This is too much boilerplate code for testing Services
@RunWith(JfxRunner.class)
public class ServiceTestableTest {
@Test
public void startServiceMultipleTimesTest() throws …{
TestService service = new TestService();
ServiceWrapper wrapper = new ServiceWrapper(service);
wrapper.startAndWait(6000);
assertEquals("I'm an expensive result. 1", wrapper.getValue());
wrapper.restartAndWait(6000);
assertEquals("I'm an expensive result. 2", wrapper.getValue());
}
}
no more
checkThread()
problems for asserts
reduces
platform issues
get help with jfx-­‐testrunner
https://github.com/sialcasa/jfx-testrunner
blocks test thread
Conclusion
there are problems testing services
you need a lot of boilerplate code to test them
use libraries
Don’t create a complex node graph in the UI Thread!
Threading and Services
but you should create Nodes in background threads!
Attach Nodes to the scene graph on the UI Thread only,
Load Data
FX-Thread
ArrayList<String> data = getBigData();
Pane displayPane = new Pane();
for (int i = 0; i < data.size(); i++) {
Label label = new Label(data.get(i));
displayPane.getChildren().add(label);
}
root.getChildren().add(displayPane);
UI-Freezes until the
Graph has been build
Display Loaded Data
Load Data
FX-Thread
ArrayList<String> data = new ArrayList<>();
Pane displayPane = new Pane();
for (int i = 0; i < data.size(); i++) {
Label label = new Label(data.get(i));
displayPane.getChildren().add(label);
}
Platform.runLater(() -> root.getChildren().add(displayPane));
Build Graph
Pixel Performance
Preprocess Metadata of Images
Pixel Performance
SimpleImageInfo	
  info	
  =	
  new	
  SimpleImageInfo(file);	
  
double	
  width	
  	
  =	
  info.getWidth();	
  
double	
  height	
  =	
  info.getHeight();
Uses meta-data in header [1]
Loading the whole image to get the Metadata is bad.
Image	
  image	
  =	
  new	
  Image("/50mp.jpg",	
  true);	
  
double	
  width	
  =	
  image.getWidth();	
  
double	
  height	
  =	
  image.getHeight();
How to preprocess the Metadata of Images?
Read- / Write Pixels
Pixel Performance
Read / Write
javafx.scene.image.PixelWriter	
  
retrieving the pixel data from an Image
writing the pixel data of a WritableImage
javafx.scene.image.PixelReader
Read Pixels Process Pixels Write Pixels
Many methods, same result…
PixelReader getArgb(…) getColor(…) getPixels(…)
setArgb(…) setColor(…) setPixels(…)PixelWriter
e.g. cropping
DEMO
Choose the right pixel format!
Pixel Performance
What is the right pixel format for Quantum Toolkit?
BYTE_BGRA_PRE
myPixelReader.setPixels(…,pixelformat	
  ,…);
myPixelReader.getPixels(…,pixelformat	
  ,…);
	
  	
  	
  	
  @Override	
  
	
  	
  	
  	
  public	
  PlatformImage	
  createPlatformImage(int	
  w,	
  int	
  h)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  ByteBuffer	
  bytebuf	
  =	
  ByteBuffer.allocate(w	
  *	
  h	
  *	
  4);	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  com.sun.prism.Image.fromByteBgraPreData(bytebuf,	
  w,	
  h);	
  
	
  	
  	
  	
  }
calls
Demo - Videoplayer using VLC & setPixels()
1. FX-Mediaplayer does not supports all codecs
2. there is no javafx.scene.media.* on ARM
VLC solves 2 additional pitfalls
Many complex nodes? Use Canvas!
Pixel Performance
Rule: use fewer nodes (>20.000 Nodes )!
picking, sync, compute dirty regions, apply CSS,….
Use Canvas / Image when you have a lot to show!
Canvas: + higher fps
+ lower heap
+ (~128MB - 250 pic.)
+ Node count 2
Node: - lower fps
- higher heap
-(~200MB - 250 pic.)
- Node count >250
Demo
Pixel Performance Conclusion
be aware of complex/many nodes
Node or Images? —> depends
choose correct PixelFormat & methods
Questions?
Hint: JavaFX Real-World Apps [CON3907]
Alexander Casall, Dirk Lemmermann
Wednesday, Oct 28, 1:00 p.m.
Links
1. http://max-wielsch.blogspot.de/2015/10/testing-asynchronous-
javafx-logic.html
2. https://jaimonmathew.wordpress.com/2011/01/29/
simpleimageinfo/
3. http://tomasmikula.github.io/blog/2015/02/10/the-trouble-
with-weak-listeners.html
4. https://blog.codecentric.de/en/2015/04/tweaking-the-menu-
bar-of-javafx-8-applications-on-os-x/
BACKUP
• JavaFX bindings uses WeakListeners to observe
dependencies
• dispose root binding should be enough
leaking Bindings
• Memory Leaks in Bindings
SimpleDoubleProperty prop = new SimpleDoubleProperty(0.0);
for (int i = 0; i < 1000000; ++i) {
prop.add(5).multiply(10).dispose();
}
prop.unbind(); // will it work?
leaking Bindings
NO!
count WeakListener = 1000000 !
count WeakReference = 1000000 !
• Memory Leaks in Bindings
SimpleDoubleProperty prop = new SimpleDoubleProperty(0.0);
leaking Bindings
prop.add(10); // invalidates all ref. !!
for (int i = 0; i < 1000000; ++i) {
prop.add(5).multiply(10).dispose();
}
chain your service execution
FX-Thread
Executor-Thread
• Solution 1 - Task & Platform.runLater
new Task<String>() {
protected String call() throws Exception {
Result r = service.get();
Platform.runLater(()-> .....);
Result r2 = service2.get();
Platform.runLater(()-> .....);
return "finished - step 2";
}
};
chain your Service execution
FX-Thread
Executor-Thread
• Platform.runLater - keeps order
• bad error handling & more !!
• Solution 2 - event handler
A.addEventHandler(SUCCEEDED, (s) -> {
updateUI();
// start next service
B.start();
});
A.addEventHandler(FAILED, (e) -> {
doThat();
updateUI();
});
B.setOnSucceeded((state) -> {
updateUI();
});
B.setOnFailed((event) -> {
doThat();
updateUI();
});
chain your Service execution
FX-Thread
Executor-Thread
• better error handling
• lots of code!
chain your Service execution
• Solution 3 - fluent API
handler
.supplyAsync(()->longRunningTask1())
.onError(this::updateErrorMessage)
.consumeOnFXThread(stringVal ->
vbox.getChildren().
add(new Button(stringVal))
)
.supplyAsync(()->longRunningTask2())
.onError(this::updateErrorMessage)
.execute(this::updateUI); //non-blocking!
FX-Thread
Executor-Thread
• good error handling
• easy to read
Test	
  service	
  with	
  fluent	
  API
final TestService service = new TestService();
IntStream.range(0, 5).forEach(v -> {
handler.supplyOnFXThread(() -> {
registerListenerAndStart(service, waitLatch);
return service;
}).functionOnExecutorThread((service) -> {
// wait outside FX application thread !!!
waitForService(waitLatch);
return service;
}).execute(serv -> {
assertEquals("I'm an expensive result.", serv.getValue());
stop.countDown();
});
awaitServiceDone(stop);
});
main thread FX thread
final TestService service = new TestService();
IntStream.range(0, 5).forEach(v -> {
handler.supplyOnFXThread(() -> {
registerListenerAndStart(service, waitLatch);
return service;
}).functionOnExecutorThread((service) -> {
// wait outside FX application thread !!!
awaitService(waitLatch);
return service;
}).execute(serv -> {
assertEquals("I'm an expensive result.", serv.getValue());
stop.countDown();
}); // Non-blocking !!!
awaitServiceResult(stop);
});
main thread FX thread worker thread
OS	
  X	
  Menu	
  Bar
OS	
  X	
  Menu	
  Bar
• JavaFX is platform independent
• no direct access to OS X application menu
OS	
  X	
  Menu	
  Bar
• Solution: Eclipse SWT -> Cocoa native binding
JavaFX wrapper: NSMenuFX [3]
better

More Related Content

What's hot

Collectors in the Wild
Collectors in the WildCollectors in the Wild
Collectors in the Wild
José Paumard
 
Curso de Java: Introdução a lambda e Streams
Curso de Java: Introdução a lambda e StreamsCurso de Java: Introdução a lambda e Streams
Curso de Java: Introdução a lambda e Streams
Helder da Rocha
 
Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introduction
Rasheed Waraich
 
Collections Api - Java
Collections Api - JavaCollections Api - Java
Collections Api - Java
Drishti Bhalla
 
Standard Template Library
Standard Template LibraryStandard Template Library
Standard Template Library
Nilesh Dalvi
 
COSCUP 2016: Project 52 每週一個小專案來學習 Golang
COSCUP 2016: Project 52 每週一個小專案來學習 GolangCOSCUP 2016: Project 52 每週一個小專案來學習 Golang
COSCUP 2016: Project 52 每週一個小專案來學習 Golang
Evan Lin
 
OSGi introduction
OSGi introductionOSGi introduction
OSGi introduction
Dario Bonino
 
An Introduction to Celery
An Introduction to CeleryAn Introduction to Celery
An Introduction to Celery
Idan Gazit
 
PHPCon China 2016 - 從學徒變大師:談 Laravel 框架擴充與套件開發
PHPCon China 2016 - 從學徒變大師:談 Laravel 框架擴充與套件開發PHPCon China 2016 - 從學徒變大師:談 Laravel 框架擴充與套件開發
PHPCon China 2016 - 從學徒變大師:談 Laravel 框架擴充與套件開發
Shengyou Fan
 
Collections - Maps
Collections - Maps Collections - Maps
Collections - Maps
Hitesh-Java
 
Collections - Lists, Sets
Collections - Lists, Sets Collections - Lists, Sets
Collections - Lists, Sets
Hitesh-Java
 
C++11
C++11C++11
Sync - Async.pptx
Sync - Async.pptxSync - Async.pptx
Sync - Async.pptx
Arturo Guillén
 
Java: Inheritance
Java: InheritanceJava: Inheritance
Java: Inheritance
Tareq Hasan
 
Introduction to java 8 stream api
Introduction to java 8 stream apiIntroduction to java 8 stream api
Introduction to java 8 stream api
Vladislav sidlyarevich
 
Spring Security 3
Spring Security 3Spring Security 3
Spring Security 3
Jason Ferguson
 
Inner classes in java
Inner classes in javaInner classes in java
Inner classes in java
PhD Research Scholar
 
Performance of Microservice frameworks on different JVMs
Performance of Microservice frameworks on different JVMsPerformance of Microservice frameworks on different JVMs
Performance of Microservice frameworks on different JVMs
Maarten Smeets
 
Sql query patterns, optimized
Sql query patterns, optimizedSql query patterns, optimized
Sql query patterns, optimized
Karwin Software Solutions LLC
 

What's hot (20)

Collectors in the Wild
Collectors in the WildCollectors in the Wild
Collectors in the Wild
 
Curso de Java: Introdução a lambda e Streams
Curso de Java: Introdução a lambda e StreamsCurso de Java: Introdução a lambda e Streams
Curso de Java: Introdução a lambda e Streams
 
Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introduction
 
Collections Api - Java
Collections Api - JavaCollections Api - Java
Collections Api - Java
 
Standard Template Library
Standard Template LibraryStandard Template Library
Standard Template Library
 
COSCUP 2016: Project 52 每週一個小專案來學習 Golang
COSCUP 2016: Project 52 每週一個小專案來學習 GolangCOSCUP 2016: Project 52 每週一個小專案來學習 Golang
COSCUP 2016: Project 52 每週一個小專案來學習 Golang
 
OSGi introduction
OSGi introductionOSGi introduction
OSGi introduction
 
An Introduction to Celery
An Introduction to CeleryAn Introduction to Celery
An Introduction to Celery
 
PHPCon China 2016 - 從學徒變大師:談 Laravel 框架擴充與套件開發
PHPCon China 2016 - 從學徒變大師:談 Laravel 框架擴充與套件開發PHPCon China 2016 - 從學徒變大師:談 Laravel 框架擴充與套件開發
PHPCon China 2016 - 從學徒變大師:談 Laravel 框架擴充與套件開發
 
Collections - Maps
Collections - Maps Collections - Maps
Collections - Maps
 
Collections - Lists, Sets
Collections - Lists, Sets Collections - Lists, Sets
Collections - Lists, Sets
 
C++11
C++11C++11
C++11
 
Sync - Async.pptx
Sync - Async.pptxSync - Async.pptx
Sync - Async.pptx
 
Java: Inheritance
Java: InheritanceJava: Inheritance
Java: Inheritance
 
Introduction to java 8 stream api
Introduction to java 8 stream apiIntroduction to java 8 stream api
Introduction to java 8 stream api
 
Spring Security 3
Spring Security 3Spring Security 3
Spring Security 3
 
Inner classes in java
Inner classes in javaInner classes in java
Inner classes in java
 
Sql injection
Sql injectionSql injection
Sql injection
 
Performance of Microservice frameworks on different JVMs
Performance of Microservice frameworks on different JVMsPerformance of Microservice frameworks on different JVMs
Performance of Microservice frameworks on different JVMs
 
Sql query patterns, optimized
Sql query patterns, optimizedSql query patterns, optimized
Sql query patterns, optimized
 

Viewers also liked

The JavaFX Ecosystem
The JavaFX EcosystemThe JavaFX Ecosystem
The JavaFX Ecosystem
Andres Almiray
 
JavaFX in Action Part I
JavaFX in Action Part IJavaFX in Action Part I
JavaFX in Action Part I
Mohammad Hossein Rimaz
 
Welches Webframework passt zu mir? (WJAX)
Welches Webframework passt zu mir? (WJAX)Welches Webframework passt zu mir? (WJAX)
Welches Webframework passt zu mir? (WJAX)
Alexander Casall
 
DataFX 8 (JavaOne 2014)
DataFX 8 (JavaOne 2014)DataFX 8 (JavaOne 2014)
DataFX 8 (JavaOne 2014)
Hendrik Ebbers
 
JavaFX Layout Secrets with Amy Fowler
JavaFX Layout Secrets with Amy FowlerJavaFX Layout Secrets with Amy Fowler
JavaFX Layout Secrets with Amy Fowler
Stephen Chin
 
Java fx ap is
Java fx ap isJava fx ap is
Java fx ap is
Tom Schindl
 
From Swing to JavaFX
From Swing to JavaFXFrom Swing to JavaFX
From Swing to JavaFX
Yuichi Sakuraba
 
Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)
Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)
Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)
Stephen Chin
 
JavaFX Your Way: Building JavaFX Applications with Alternative Languages
JavaFX Your Way: Building JavaFX Applications with Alternative LanguagesJavaFX Your Way: Building JavaFX Applications with Alternative Languages
JavaFX Your Way: Building JavaFX Applications with Alternative Languages
Stephen Chin
 
A Tour of PostgREST
A Tour of PostgRESTA Tour of PostgREST
A Tour of PostgREST
begriffs
 
JavaFX in Action (devoxx'16)
JavaFX in Action (devoxx'16)JavaFX in Action (devoxx'16)
JavaFX in Action (devoxx'16)
Alexander Casall
 
JavaFX Overview
JavaFX OverviewJavaFX Overview
JavaFX Overview
José Maria Silveira Neto
 
JavaFX Real-World Apps
JavaFX Real-World AppsJavaFX Real-World Apps
JavaFX Real-World Apps
Alexander Casall
 
JavaFX GUI architecture with Clojure core.async
JavaFX GUI architecture with Clojure core.asyncJavaFX GUI architecture with Clojure core.async
JavaFX GUI architecture with Clojure core.async
Falko Riemenschneider
 
FlatGUI: Reactive GUI Toolkit Implemented in Clojure
FlatGUI: Reactive GUI Toolkit Implemented in ClojureFlatGUI: Reactive GUI Toolkit Implemented in Clojure
FlatGUI: Reactive GUI Toolkit Implemented in Clojure
denyslebediev
 
8 True Stories about JavaFX
8 True Stories about JavaFX8 True Stories about JavaFX
8 True Stories about JavaFX
Yuichi Sakuraba
 
JavaFX 8 - GUI by Illusion
JavaFX 8 - GUI by IllusionJavaFX 8 - GUI by Illusion
JavaFX 8 - GUI by Illusion
Yuichi Sakuraba
 
JavaFX Presentation
JavaFX PresentationJavaFX Presentation
JavaFX Presentation
Mochamad Taufik Mulyadi
 
What's New in Java 8
What's New in Java 8What's New in Java 8
What's New in Java 8
javafxpert
 
Clojure #1
Clojure #1Clojure #1

Viewers also liked (20)

The JavaFX Ecosystem
The JavaFX EcosystemThe JavaFX Ecosystem
The JavaFX Ecosystem
 
JavaFX in Action Part I
JavaFX in Action Part IJavaFX in Action Part I
JavaFX in Action Part I
 
Welches Webframework passt zu mir? (WJAX)
Welches Webframework passt zu mir? (WJAX)Welches Webframework passt zu mir? (WJAX)
Welches Webframework passt zu mir? (WJAX)
 
DataFX 8 (JavaOne 2014)
DataFX 8 (JavaOne 2014)DataFX 8 (JavaOne 2014)
DataFX 8 (JavaOne 2014)
 
JavaFX Layout Secrets with Amy Fowler
JavaFX Layout Secrets with Amy FowlerJavaFX Layout Secrets with Amy Fowler
JavaFX Layout Secrets with Amy Fowler
 
Java fx ap is
Java fx ap isJava fx ap is
Java fx ap is
 
From Swing to JavaFX
From Swing to JavaFXFrom Swing to JavaFX
From Swing to JavaFX
 
Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)
Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)
Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)
 
JavaFX Your Way: Building JavaFX Applications with Alternative Languages
JavaFX Your Way: Building JavaFX Applications with Alternative LanguagesJavaFX Your Way: Building JavaFX Applications with Alternative Languages
JavaFX Your Way: Building JavaFX Applications with Alternative Languages
 
A Tour of PostgREST
A Tour of PostgRESTA Tour of PostgREST
A Tour of PostgREST
 
JavaFX in Action (devoxx'16)
JavaFX in Action (devoxx'16)JavaFX in Action (devoxx'16)
JavaFX in Action (devoxx'16)
 
JavaFX Overview
JavaFX OverviewJavaFX Overview
JavaFX Overview
 
JavaFX Real-World Apps
JavaFX Real-World AppsJavaFX Real-World Apps
JavaFX Real-World Apps
 
JavaFX GUI architecture with Clojure core.async
JavaFX GUI architecture with Clojure core.asyncJavaFX GUI architecture with Clojure core.async
JavaFX GUI architecture with Clojure core.async
 
FlatGUI: Reactive GUI Toolkit Implemented in Clojure
FlatGUI: Reactive GUI Toolkit Implemented in ClojureFlatGUI: Reactive GUI Toolkit Implemented in Clojure
FlatGUI: Reactive GUI Toolkit Implemented in Clojure
 
8 True Stories about JavaFX
8 True Stories about JavaFX8 True Stories about JavaFX
8 True Stories about JavaFX
 
JavaFX 8 - GUI by Illusion
JavaFX 8 - GUI by IllusionJavaFX 8 - GUI by Illusion
JavaFX 8 - GUI by Illusion
 
JavaFX Presentation
JavaFX PresentationJavaFX Presentation
JavaFX Presentation
 
What's New in Java 8
What's New in Java 8What's New in Java 8
What's New in Java 8
 
Clojure #1
Clojure #1Clojure #1
Clojure #1
 

Similar to JavaFX Pitfalls

Programming Sideways: Asynchronous Techniques for Android
Programming Sideways: Asynchronous Techniques for AndroidProgramming Sideways: Asynchronous Techniques for Android
Programming Sideways: Asynchronous Techniques for Android
Emanuele Di Saverio
 
Maxim Salnikov - Service Worker: taking the best from the past experience for...
Maxim Salnikov - Service Worker: taking the best from the past experience for...Maxim Salnikov - Service Worker: taking the best from the past experience for...
Maxim Salnikov - Service Worker: taking the best from the past experience for...
Codemotion
 
Divide and Conquer – Microservices with Node.js
Divide and Conquer – Microservices with Node.jsDivide and Conquer – Microservices with Node.js
Divide and Conquer – Microservices with Node.js
Sebastian Springer
 
Is writing performant code too expensive?
Is writing performant code too expensive? Is writing performant code too expensive?
Is writing performant code too expensive?
Tomasz Kowalczewski
 
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
Igor Bronovskyy
 
Das kannste schon so machen
Das kannste schon so machenDas kannste schon so machen
Das kannste schon so machen
André Goliath
 
JavaScript (without DOM)
JavaScript (without DOM)JavaScript (without DOM)
JavaScript (without DOM)Piyush Katariya
 
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
Fwdays
 
Why Windows 8 drivers are buggy
Why Windows 8 drivers are buggyWhy Windows 8 drivers are buggy
Why Windows 8 drivers are buggy
Andrey Karpov
 
ZCM update VAI Brainforce
ZCM update VAI BrainforceZCM update VAI Brainforce
ZCM update VAI Brainforce
Roel van Bueren
 
Lagom in Practice
Lagom in PracticeLagom in Practice
Lagom in Practice
JWORKS powered by Ordina
 
WSO2 SOA with C and C++
WSO2 SOA with C and C++WSO2 SOA with C and C++
WSO2 SOA with C and C++WSO2
 
Jdk Tools For Performance Diagnostics
Jdk Tools For Performance DiagnosticsJdk Tools For Performance Diagnostics
Jdk Tools For Performance Diagnostics
Dror Bereznitsky
 
From Web App Model Design to Production with Wakanda
From Web App Model Design to Production with WakandaFrom Web App Model Design to Production with Wakanda
From Web App Model Design to Production with Wakanda
Alexandre Morgaut
 
NestJS
NestJSNestJS
NestJS
Wilson Su
 
Javascript Memory leaks and Performance & Angular
Javascript Memory leaks and Performance & AngularJavascript Memory leaks and Performance & Angular
Javascript Memory leaks and Performance & Angular
Erik Guzman
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.js
soft-shake.ch
 
Virtualizing Java in Java (jug.ru)
Virtualizing Java in Java (jug.ru)Virtualizing Java in Java (jug.ru)
Virtualizing Java in Java (jug.ru)
aragozin
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developers
Pavel Lahoda
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon Berlin
 

Similar to JavaFX Pitfalls (20)

Programming Sideways: Asynchronous Techniques for Android
Programming Sideways: Asynchronous Techniques for AndroidProgramming Sideways: Asynchronous Techniques for Android
Programming Sideways: Asynchronous Techniques for Android
 
Maxim Salnikov - Service Worker: taking the best from the past experience for...
Maxim Salnikov - Service Worker: taking the best from the past experience for...Maxim Salnikov - Service Worker: taking the best from the past experience for...
Maxim Salnikov - Service Worker: taking the best from the past experience for...
 
Divide and Conquer – Microservices with Node.js
Divide and Conquer – Microservices with Node.jsDivide and Conquer – Microservices with Node.js
Divide and Conquer – Microservices with Node.js
 
Is writing performant code too expensive?
Is writing performant code too expensive? Is writing performant code too expensive?
Is writing performant code too expensive?
 
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
 
Das kannste schon so machen
Das kannste schon so machenDas kannste schon so machen
Das kannste schon so machen
 
JavaScript (without DOM)
JavaScript (without DOM)JavaScript (without DOM)
JavaScript (without DOM)
 
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
 
Why Windows 8 drivers are buggy
Why Windows 8 drivers are buggyWhy Windows 8 drivers are buggy
Why Windows 8 drivers are buggy
 
ZCM update VAI Brainforce
ZCM update VAI BrainforceZCM update VAI Brainforce
ZCM update VAI Brainforce
 
Lagom in Practice
Lagom in PracticeLagom in Practice
Lagom in Practice
 
WSO2 SOA with C and C++
WSO2 SOA with C and C++WSO2 SOA with C and C++
WSO2 SOA with C and C++
 
Jdk Tools For Performance Diagnostics
Jdk Tools For Performance DiagnosticsJdk Tools For Performance Diagnostics
Jdk Tools For Performance Diagnostics
 
From Web App Model Design to Production with Wakanda
From Web App Model Design to Production with WakandaFrom Web App Model Design to Production with Wakanda
From Web App Model Design to Production with Wakanda
 
NestJS
NestJSNestJS
NestJS
 
Javascript Memory leaks and Performance & Angular
Javascript Memory leaks and Performance & AngularJavascript Memory leaks and Performance & Angular
Javascript Memory leaks and Performance & Angular
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.js
 
Virtualizing Java in Java (jug.ru)
Virtualizing Java in Java (jug.ru)Virtualizing Java in Java (jug.ru)
Virtualizing Java in Java (jug.ru)
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developers
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahoda
 

Recently uploaded

Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
NYGGS Automation Suite
 
Using IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New ZealandUsing IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New Zealand
IES VE
 
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Mind IT Systems
 
2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx
Georgi Kodinov
 
RISE with SAP and Journey to the Intelligent Enterprise
RISE with SAP and Journey to the Intelligent EnterpriseRISE with SAP and Journey to the Intelligent Enterprise
RISE with SAP and Journey to the Intelligent Enterprise
Srikant77
 
How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
Globus
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
Google
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
Cyanic lab
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with Platformless
WSO2
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
Ortus Solutions, Corp
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
Ortus Solutions, Corp
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
Philip Schwarz
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Globus
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
abdulrafaychaudhry
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
Tendenci - The Open Source AMS (Association Management Software)
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
wottaspaceseo
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus
 

Recently uploaded (20)

Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
 
Using IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New ZealandUsing IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New Zealand
 
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
 
2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx
 
RISE with SAP and Journey to the Intelligent Enterprise
RISE with SAP and Journey to the Intelligent EnterpriseRISE with SAP and Journey to the Intelligent Enterprise
RISE with SAP and Journey to the Intelligent Enterprise
 
How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with Platformless
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
 

JavaFX Pitfalls

  • 1. Know them, or you will get angry. JavaFX Pitfalls CON4789
  • 3. Speaker @sialcasa Alexander Casall Software Architect & Scrum Product Owner Custom Software Development Company in Germany Dresden, Munich, Berlin, Hamburg, Leipzig… 225 employees 3 Scrum Teams in JavaFX Projects ±7 consultants supporting JavaFX projects on customer side alexander.casall@saxsys.de
  • 4. Speaker Andy Moncsek Senior Consultant Application Development Trivadis AG Switzerland - Zürich 600 employees in Switzerland, Germany and Austria consulting, development, BI, infrastructure, operation andy.moncsek@trivadis.com @andyahcp
  • 5. FXML / Caching Memory Threading and Services Pixel Operations Examples https://github.com/sialcasa/javafx-pitfalls
  • 6. Before we start: If you are looking for common performance tipps regarding JavaFX https://wiki.openjdk.java.net/display/OpenJFX/Performance+Tips+and+Tricks
  • 9.
  • 10. <?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.chart.*?> <?import javafx.scene.shape.*?> <?import javafx.scene.text.*?> <?import javafx.scene.control.*?> <?import java.lang.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.layout.AnchorPane?> <AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40"> <children> <BorderPane prefHeight="200.0" prefWidth="200.0"> <center> <SplitPane dividerPositions="0.29797979797979796" prefHeight="160.0" prefWidth="200.0" Bord <items> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" /> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0"> <children> <TabPane layoutX="-32.0" layoutY="-31.0" prefHeight="200.0" prefWidth="200.0" t <tabs> <Tab text="Untitled Tab 1"> <content> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth <children> <TextFlow layoutX="-86.0" layoutY="-30.0" prefHeight="200.0" <children> <TitledPane animated="false" text="untitled"> <content> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeig <children>
  • 11. DEMO
  • 12. Conclusion wildcard imports are bad - check your FXML files IntelliJ IDEA has import optimisation We’ll fix this issue on Scene Builder
  • 13. Why you don’t use caching? FXML / Caching
  • 14. What caching does extends  Node myMagicalCircle.setCache(true); Image
  • 15. Why should you use it?
  • 16. magical circles are expensive to render GPU
  • 17. The movement of the element causes rendering effort GPU
  • 18. GPU Other nodes can also cause rendering
  • 19. Caching avoids unnecessary rendering of nodes Why should you use it?
  • 20. GPU myMagicalCircle.setCache(true) no more rendering caused e.g. by movement or overlapping nodes
  • 21. Demo
  • 22. Conclusion simple objects which change often complex objects which don’t change (Don’t) cache…
  • 24. Listener can cause memory leaks Memory
  • 25. public class TemporaryView extends StackPane { public TemporaryView(Car dataModel) { dataModel.name.addListener(new ChangeListener<String>() { @Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { //Do Something } }); } } public class Car { StringProperty name = new SimpleStringProperty("Audi"); } Instances of anonymous inner classes hold on to a reference to their enclosing instances even if these references are never actually used. references
  • 26. @Override public void start(Stage primaryStage) throws Exception { this.longlivingData = new Car(); this.root = new VBox(new TemporaryView(longlivingData)); Scene scene = new Scene(root); primaryStage.setScene(scene); primaryStage.show(); } VBox in Stage Temporary View long living Data Model
  • 27. root.getChildren().clear(); Application Lifetime VBox in Stage Temporary View long living Data Model Temporary View
  • 28. Application Lifetime VBox in Stage Temporary View long living Data Model Temporary View retains in memory omg, it’s a leak
  • 29. How to avoid it? Use WeakListener (dangerous) Do manual Housekeeping
  • 30. Demo
  • 31. Conclusion Listeners can leak WeakListeners are dangerous manage your Listeners manually avoid anonymous implementations
  • 32. Be aware of lost listeners! Memory
  • 33. DoubleProperty one=…; DoubleProperty two=…; this.one.add(this.two). addListener((x, y, z) -> { if (z != null && z.intValue() == 10) { Alert alert = new Alert(…); alert.showAndWait(); } }); The listener get’s garbage collected Same as:
  • 34. DoubleProperty one=…; DoubleProperty two=…; NumberBinding add = Bindings.add(one, two); add.addListener((x, y, z) -> { if (z != null && z.intValue() == 10) { Alert alert = new Alert(…); alert.showAndWait(); } }); The listener get’s garbage collected
  • 35. DEMO
  • 36. Conclusion - reference the binding DoubleProperty one=…; DoubleProperty two=…; this.add = Bindings.add(one, two); this.add.addListener((x, y, z) -> { if (z != null && z.intValue() == 10) { Alert alert = new Alert(…); alert.showAndWait(); } });
  • 38. It’s hard to test JavaFX Services! Threading and Services
  • 39. public class TestService extends Service<String> { @Override protected Task<String> createTask() { return new Task<String>() { @Override protected String call() throws Exception { Thread.sleep(5000); return "I'm an expensive result."; } }; } } How to test this?
  • 40. Not FX specific: How to test async behaviour?
  • 41. @Test public void testLongLastingOperation() throws … { TestService service = new TestService(); CompletableFuture<String> future = new CompletableFuture<>(); service.valueProperty().addListener((b, o, n) -> { if (n != null) { future.complete(n); } }); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); } Green or Red?
  • 42.
  • 43. java.lang.IllegalStateException:  Toolkit  not  initialized     at  com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:   at  com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:   at  javafx.application.Platform.runLater(Platform.java:83)     at  javafx.concurrent.Service.runLater(Service.java:913)     at  javafx.concurrent.Service.start(Service.java:676)   …  
  • 44. @Test public void testLongLastingOperation() throws … { TestService service = new TestService(); CompletableFuture<String> future = new CompletableFuture<>(); service.valueProperty().addListener((b, o, n) -> { if (n != null) { future.complete(n); } }); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); } Green or Red? Needs started FX-Toolkit
  • 46. @RunWith(JfxRunner.class) public class ServiceNotTestableTest { @Test public void testLongLastingOperation() throws … { TestService service = new TestService(); CompletableFuture<String> future = new CompletableFuture<>(); service.valueProperty().addListener((b, o, n) -> { if (n != null) { future.complete(n); } }); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); } <dependency> <groupId>de.saxsys</groupId> <artifactId>jfx-testrunner</artifactId> <version>1.2-SNAPSHOT</version> </dependency>
  • 47.
  • 48. But… The Service has the intention to be reused multiple times. Let’s test this!
  • 49. Let’s do a small refactoring @RunWith(JfxRunner.class) public class TestableServiceTest { @Test public void testLongLastingOperation() throws … { TestService service = new TestService(); CompletableFuture<String> future = new CompletableFuture<>(); service.valueProperty().addListener((b, o, n) -> { if (n != null) { future.complete(n); } }); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); }
  • 50. @RunWith(JfxRunner.class) public class TestableServiceTest { @Test public void testLongLastingOperation() throws … { TestService service = new TestService(); //refactored the Completable future stuff with the listeners in a method CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); } }
  • 51. @RunWith(JfxRunner.class) public class TestableServiceTest { @Test public void testLongLastingOperation() throws … { TestService service = new TestService(); //refactored the Completable future stuff with the listeners in a method CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); } } Green or Red?
  • 52.
  • 53. java.lang.IllegalStateException:  Service  must   only  be  used  from  the  FX  Application  Thread     at  javafx.concurrent.Service.checkThread(Service.java:906)     at  javafx.concurrent.Service.valueProperty(Service.java:205)     at   de.saxsys.pitfalls.services.ClassToTestTest.testLongLastingOperation(ClassToTestTest.java: 40)     at  sun.reflect.NativeMethodAccessorImpl.invoke0(Native  Method)     at  sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     at  sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:  
  • 54. @RunWith(JfxRunner.class) public class TestableServiceTest { @Test public void testLongLastingOperation() throws … { TestService service = new TestService(); //refactored the Completable future stuff with the listeners in a method CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); } } Exception goes here
  • 55. Let’s have a look on the Service Implementation @Override public final V getValue() { checkThread(); return value.get(); } @Override public final ReadOnlyObjectProperty<V> valueProperty() { checkThread(); return value;} /** * Cancels any currently running Task, if any, and restarts this Service. The state * will be reset to READY prior to execution. This method should only be called on * the FX application thread. */ public void restart() { checkThread(); … } void checkThread() { if (startedOnce && !isFxApplicationThread()) { throw new IllegalStateException("Service must only be used from the FX Application Thread"); } }
  • 57. But I wan’t to call my service multiple times in my test - because this is it’s use-case.
  • 58.
  • 59. Let’s test this in the FX- Thread
  • 60. @RunWith(JfxRunner.class) public class TestableServiceTest { @Test public void testLongLastingOperation() throws … { TestService service = new TestService(); //refactored the Completable future stuff with the listeners in a method CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); } }
  • 61. @RunWith(JfxRunner.class) public class TestableServiceTest { @Test @TestInJfxThread public void testLongLastingOperation() throws … { TestService service = new TestService(); //refactored the Completable future stuff with the listeners in a method CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); } } jfx-testrunner annotation
  • 62. @RunWith(JfxRunner.class) public class TestableServiceTest { @Test @TestInJfxThread public void testLongLastingOperation() throws … { TestService service = new TestService(); //refactored the Completable future stuff with the listeners in a method CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); } } Green or Red?
  • 63.
  • 64. java.util.concurrent.TimeoutException at java.util.concurrent.CompletableFuture.timedGet(CompletableFuture.java:1763) at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1907) at de.saxsys.pitfalls.services.nottestable.ServiceNotTestableTest.testLongLastingOperationInFXThread( TestServiceTest.java:85) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at de.saxsys.javafx.test.JfxRunner.access$0(JfxRunner.java:1) at de.saxsys.javafx.test.JfxRunner.lambda$0(JfxRunner.java:47) at de.saxsys.javafx.test.JfxRunner$$Lambda$56/1865127310.run(Unknown Source) at com.sun.javafx.application.PlatformImpl.lambda$null$170(PlatformImpl.java:295) at com.sun.javafx.application.PlatformImpl$$Lambda$52/1724593206.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at com.sun.javafx.application.PlatformImpl.lambda$runLater$171(PlatformImpl.java:294) at com.sun.javafx.application.PlatformImpl$$Lambda$51/580016451.run(Unknown Source) at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
  • 65. @RunWith(JfxRunner.class) public class TestableServiceTest { @Test @TestInJfxThread public void testLongLastingOperation() throws … { TestService service = new TestService(); //refactored the Completable future stuff with the listeners in a method CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); CompletableFuture<String> future = createFutureWithListener(service); service.restart(); assertEquals("I'm an expensive result.", future.get(5, TimeUnit.SECONDS)); } } Line 85: .get() blocks the UI Thread
  • 66. Ok, correct solution: start with Test Thread and move all Service accesses to FX Thread
  • 67. FX Thread @Test public void testLongLastingOperationSimple() throws … { TestService service = new TestService(); CompletableFuture<String> future = new CompletableFuture<>(); Platform.runLater(() -> { service.valueProperty().addListener((b, o, n) -> { if (n != null) { future.complete(n); } }); service.restart(); }); assertEquals("I'm an expensive result. 1", future.get(5, TimeUnit.SECONDS)); }
  • 68.
  • 69. Ok, let’s run and test the Service multiple times
  • 70. @Test public void testLongLastingOperationSimple() throws … { TestService service = new TestService(); CompletableFuture<String> future = new CompletableFuture<>(); Platform.runLater(() -> { service.valueProperty().addListener((b, o, n) -> { if (n != null) { future.complete(n); } }); service.restart(); }); assertEquals("I'm an expensive result. 1", future.get(5, TimeUnit.SECONDS)); CompletableFuture<String> future = new CompletableFuture<>(); Platform.runLater(() -> { service.valueProperty().addListener((b, o, n) -> { if (n != null) { future.complete(n); } }); service.restart(); }); assertEquals("I'm an expensive result. 1", future.get(5, TimeUnit.SECONDS)); } For each execution of the Service you have to double the amount of the (boilerplate)-code.
  • 71. This is too much boilerplate code for testing Services
  • 72. @RunWith(JfxRunner.class) public class ServiceTestableTest { @Test public void startServiceMultipleTimesTest() throws …{ TestService service = new TestService(); ServiceWrapper wrapper = new ServiceWrapper(service); wrapper.startAndWait(6000); assertEquals("I'm an expensive result. 1", wrapper.getValue()); wrapper.restartAndWait(6000); assertEquals("I'm an expensive result. 2", wrapper.getValue()); } } no more checkThread() problems for asserts reduces platform issues get help with jfx-­‐testrunner https://github.com/sialcasa/jfx-testrunner blocks test thread
  • 73. Conclusion there are problems testing services you need a lot of boilerplate code to test them use libraries
  • 74. Don’t create a complex node graph in the UI Thread! Threading and Services
  • 75. but you should create Nodes in background threads! Attach Nodes to the scene graph on the UI Thread only,
  • 76. Load Data FX-Thread ArrayList<String> data = getBigData(); Pane displayPane = new Pane(); for (int i = 0; i < data.size(); i++) { Label label = new Label(data.get(i)); displayPane.getChildren().add(label); } root.getChildren().add(displayPane); UI-Freezes until the Graph has been build Display Loaded Data
  • 77. Load Data FX-Thread ArrayList<String> data = new ArrayList<>(); Pane displayPane = new Pane(); for (int i = 0; i < data.size(); i++) { Label label = new Label(data.get(i)); displayPane.getChildren().add(label); } Platform.runLater(() -> root.getChildren().add(displayPane)); Build Graph
  • 79. Preprocess Metadata of Images Pixel Performance
  • 80. SimpleImageInfo  info  =  new  SimpleImageInfo(file);   double  width    =  info.getWidth();   double  height  =  info.getHeight(); Uses meta-data in header [1] Loading the whole image to get the Metadata is bad. Image  image  =  new  Image("/50mp.jpg",  true);   double  width  =  image.getWidth();   double  height  =  image.getHeight(); How to preprocess the Metadata of Images?
  • 81. Read- / Write Pixels Pixel Performance
  • 82. Read / Write javafx.scene.image.PixelWriter   retrieving the pixel data from an Image writing the pixel data of a WritableImage javafx.scene.image.PixelReader Read Pixels Process Pixels Write Pixels
  • 83. Many methods, same result… PixelReader getArgb(…) getColor(…) getPixels(…) setArgb(…) setColor(…) setPixels(…)PixelWriter e.g. cropping
  • 84. DEMO
  • 85. Choose the right pixel format! Pixel Performance
  • 86. What is the right pixel format for Quantum Toolkit? BYTE_BGRA_PRE myPixelReader.setPixels(…,pixelformat  ,…); myPixelReader.getPixels(…,pixelformat  ,…);        @Override          public  PlatformImage  createPlatformImage(int  w,  int  h)  {                  ByteBuffer  bytebuf  =  ByteBuffer.allocate(w  *  h  *  4);                  return  com.sun.prism.Image.fromByteBgraPreData(bytebuf,  w,  h);          } calls
  • 87. Demo - Videoplayer using VLC & setPixels() 1. FX-Mediaplayer does not supports all codecs 2. there is no javafx.scene.media.* on ARM VLC solves 2 additional pitfalls
  • 88. Many complex nodes? Use Canvas! Pixel Performance
  • 89. Rule: use fewer nodes (>20.000 Nodes )! picking, sync, compute dirty regions, apply CSS,…. Use Canvas / Image when you have a lot to show!
  • 90. Canvas: + higher fps + lower heap + (~128MB - 250 pic.) + Node count 2 Node: - lower fps - higher heap -(~200MB - 250 pic.) - Node count >250 Demo
  • 91. Pixel Performance Conclusion be aware of complex/many nodes Node or Images? —> depends choose correct PixelFormat & methods
  • 92. Questions? Hint: JavaFX Real-World Apps [CON3907] Alexander Casall, Dirk Lemmermann Wednesday, Oct 28, 1:00 p.m.
  • 93. Links 1. http://max-wielsch.blogspot.de/2015/10/testing-asynchronous- javafx-logic.html 2. https://jaimonmathew.wordpress.com/2011/01/29/ simpleimageinfo/ 3. http://tomasmikula.github.io/blog/2015/02/10/the-trouble- with-weak-listeners.html 4. https://blog.codecentric.de/en/2015/04/tweaking-the-menu- bar-of-javafx-8-applications-on-os-x/
  • 95. • JavaFX bindings uses WeakListeners to observe dependencies • dispose root binding should be enough leaking Bindings
  • 96. • Memory Leaks in Bindings SimpleDoubleProperty prop = new SimpleDoubleProperty(0.0); for (int i = 0; i < 1000000; ++i) { prop.add(5).multiply(10).dispose(); } prop.unbind(); // will it work? leaking Bindings NO! count WeakListener = 1000000 ! count WeakReference = 1000000 !
  • 97. • Memory Leaks in Bindings SimpleDoubleProperty prop = new SimpleDoubleProperty(0.0); leaking Bindings prop.add(10); // invalidates all ref. !! for (int i = 0; i < 1000000; ++i) { prop.add(5).multiply(10).dispose(); }
  • 98. chain your service execution FX-Thread Executor-Thread
  • 99. • Solution 1 - Task & Platform.runLater new Task<String>() { protected String call() throws Exception { Result r = service.get(); Platform.runLater(()-> .....); Result r2 = service2.get(); Platform.runLater(()-> .....); return "finished - step 2"; } }; chain your Service execution FX-Thread Executor-Thread • Platform.runLater - keeps order • bad error handling & more !!
  • 100. • Solution 2 - event handler A.addEventHandler(SUCCEEDED, (s) -> { updateUI(); // start next service B.start(); }); A.addEventHandler(FAILED, (e) -> { doThat(); updateUI(); }); B.setOnSucceeded((state) -> { updateUI(); }); B.setOnFailed((event) -> { doThat(); updateUI(); }); chain your Service execution FX-Thread Executor-Thread • better error handling • lots of code!
  • 101. chain your Service execution • Solution 3 - fluent API handler .supplyAsync(()->longRunningTask1()) .onError(this::updateErrorMessage) .consumeOnFXThread(stringVal -> vbox.getChildren(). add(new Button(stringVal)) ) .supplyAsync(()->longRunningTask2()) .onError(this::updateErrorMessage) .execute(this::updateUI); //non-blocking! FX-Thread Executor-Thread • good error handling • easy to read
  • 102. Test  service  with  fluent  API
  • 103. final TestService service = new TestService(); IntStream.range(0, 5).forEach(v -> { handler.supplyOnFXThread(() -> { registerListenerAndStart(service, waitLatch); return service; }).functionOnExecutorThread((service) -> { // wait outside FX application thread !!! waitForService(waitLatch); return service; }).execute(serv -> { assertEquals("I'm an expensive result.", serv.getValue()); stop.countDown(); }); awaitServiceDone(stop); }); main thread FX thread
  • 104. final TestService service = new TestService(); IntStream.range(0, 5).forEach(v -> { handler.supplyOnFXThread(() -> { registerListenerAndStart(service, waitLatch); return service; }).functionOnExecutorThread((service) -> { // wait outside FX application thread !!! awaitService(waitLatch); return service; }).execute(serv -> { assertEquals("I'm an expensive result.", serv.getValue()); stop.countDown(); }); // Non-blocking !!! awaitServiceResult(stop); }); main thread FX thread worker thread
  • 105. OS  X  Menu  Bar
  • 106. OS  X  Menu  Bar • JavaFX is platform independent • no direct access to OS X application menu
  • 107. OS  X  Menu  Bar • Solution: Eclipse SWT -> Cocoa native binding JavaFX wrapper: NSMenuFX [3] better