javafx pitfalls
play

JavaFX Pitfalls What no documentation tells you Speaker Andy - PowerPoint PPT Presentation

JavaFX Pitfalls What no documentation tells you Speaker Andy Moncsek Senior Consultant Application Development @andyahcp Trivadis AG Switzerland - Zrich 600 employees in Switzerland, Germany and Austria consulting, development, BI,


  1. JavaFX Pitfalls What no documentation tells you…

  2. Speaker Andy Moncsek Senior Consultant Application Development @andyahcp Trivadis AG Switzerland - Zürich 600 employees in Switzerland, Germany and Austria consulting, development, BI, infrastructure, operation andy.moncsek@trivadis.com

  3. Overall Performance Pitfall - lost Listeners

  4. lost Listeners • Accidental Garbage Collection Bindings. add(one, two). addListener((x, y, z) -> { if (z != null && z.intValue() == 10) { Alert alert = new Alert(INFORMATION); alert.showAndWait(); } }); Same as:

  5. lost Listeners • Accidental Garbage Collection DoubleBinding b = Bindings.add(one, two); b.addListener((x, y, z) -> { if (z != null && z.intValue() == 10) { Alert alert = new Alert(INFORMATION); alert.showAndWait(); } });

  6. lost Listeners better: this .b = Bindings.add(one, two); this .b.addListener((x, y, z) -> { if (z != null && z.intValue() == 10) { Alert alert = new Alert(INFORMATION); alert.showAndWait(); } }); keep a reference of your binding

  7. Solution? Use a custom implementation for async things, if you can’t life with the pitfalls.

  8. @RunWith(JfxRunner.class) public class TestServiceTest { @Test public void testLongLastingOperation() { final TestService service = new TestService(); CompletableFuture<String> f = new CompletableFuture<>(); Platform.runLater(() -> { service.valueProperty().addListener((b, o, n) -> { if (n != null) { f.complete(n); } }); service.restart(); }); assertEquals(„..“, future.get(5, TimeUnit.SECONDS)); } } main thread

  9. @RunWith(JfxRunner.class) public class TestServiceTest { @Test public void testLongLastingOperation() { final TestService service = new TestService(); CompletableFuture<String> f = new CompletableFuture<>(); Platform.runLater(() -> { service.valueProperty().addListener((b, o, n) -> { if (n != null) { f.complete(n); } }); service.restart(); }); assertEquals(„..“, future.get(5, TimeUnit.SECONDS)); } } main thread FX thread

  10. @RunWith(JfxRunner.class) public class TestServiceTest { @Test public void testLongLastingOperation() { final TestService service = new TestService(); CompletableFuture<String> f = new CompletableFuture<>(); Platform.runLater(() -> { service.valueProperty().addListener((b, o, n) -> { if (n != null) { f.complete(n); } }); service.restart(); }); assertEquals(„..“, f.get(5, TimeUnit.SECONDS)); } } main thread FX thread

  11. Conclusion there are big problems testing services you can ignore it use own implementations

  12. Async Pitfalls Don’t create a complex node graph in the UI Thread

  13. Threads, Tasks and Services • not in FX - Thread? -> do not touch Nodes! • create Nodes -> when not in SceneGraph OK • take care of callbacks from other frameworks (WebSocket, ...)

  14. Threads, Tasks and Services public class MyApp extends Application { @Override public void init() throws Exception { // Do some heavy lifting } @Override public void start(Stage primaryStage) throws Exception { ... primaryStage.show(); } public static void main(String[] args) { LauncherImpl.launchApplication(MyApp.class,Preloader.class, args); } }

  15. Threads, Tasks and Services public class MyApp extends Application { @Override public void init() throws Exception { // Do some heavy lifting } @Override public void start(Stage primaryStage) throws Exception { ... primaryStage.show(); } public static void main(String[] args) { LauncherImpl.launchApplication(MyApp.class,Preloader.class, args); } } FX launcher thread FX thread

  16. Threads, Tasks and Services public class MyApp extends Application { private InitialUIService service = new InitialUIService(); @Override public void init() throws Exception { // Do some heavy lifting service.start(); } @Override public void start(Stage primaryStage) throws Exception { ... primaryStage.show(); } public static void main(String[] args) { LauncherImpl.launchApplication(MyApp.class,Preloader.class, args); } } FX launcher thread FX thread Worker thread

  17. Pixel Performance

  18. Pushing - Pixels image size • know the image size before loading Do not load the whole image ! Image image = new Image("/50mp.jpg", true); double width = image.getWidth(); double height = image.getHeight(); Uses meta-data in header [1] SimpleImageInfo info = new SimpleImageInfo(file); double width = info.getWidth(); double height = info.getHeight();

  19. Pushing - Pixels read/write • PixelWriter • writing the pixel data of a WritableImage • PixelReader • retrieving the pixel data from an Image • Get pixel -> manipulate -> write pixel

  20. Pushing Pixels read/write PixelReader PixelWriter getArgb(x,y) setArgb(x,y,value) VS. getColor(x,y) setColor(x,y,value) getPixels(…) setPixels(…)

  21. Example : Crop an image Demo

  22. Pushing Pixels PixelFormat • Choose the right PixelFormat -> setPixels(…) • INT_ARGB_PRE, INT_ARGB, BYTE_BGRA new WriteableImage() -> QuantumToolkit public PlatformImage createPlatformImage(int w, int h) { ByteBuffer bytebuf = ...; return com.sun.prism.Image.fromByteBgraPreData(bytebuf, w, h); }

  23. Pushing Pixels PixelFormat • Play video in JavaFX using VLC & setPixels(…) • video fortmat! • no MediaPlayer on ARM Demo

  24. Pushing - Pixels • Rule 1: use viewer nodes (~20.000 Nodes )! • picking, sync, compute dirty regions, apply CSS,…. • Custom Controls —> x Nodes? complex CSS? • Use Canvas / Image when you have a lot to show!

  25. Pushing - Pixels Canvas : + higher fps Node : - lower fps + lower heap - higher heap + (~128MB - 250 pic.) -(~200MB - 250 pic.) + Node count 2 - Node count >250

  26. Conclusion be aware of complex/many nodes Node or Images? —> depends choose correct PixelFormat & methods

  27. Questions?

  28. Links 1. https://jaimonmathew.wordpress.com/2011/01/29/ simpleimageinfo/ 2. http://tomasmikula.github.io/blog/2015/02/10/ the-trouble-with-weak-listeners.html 3. https://blog.codecentric.de/en/2015/04/ tweaking-the-menu-bar-of-javafx-8-applications- on-os-x/

  29. BACKUP

  30. leaking Bindings • JavaFX bindings uses WeakListeners to observe dependencies • dispose root binding should be enough

  31. 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? NO! count WeakListener = 1000000 ! count WeakReference = 1000000 !

  32. 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.add(10); // invalidates all ref. !!

  33. chain your service execution Executor-Thread FX-Thread

  34. chain your Service execution • 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"; } }; • Platform.runLater - keeps order • bad error handling & more !! Executor-Thread FX-Thread

  35. chain your Service execution • Solution 2 - event handler B .setOnSucceeded((state) -> { A .addEventHandler(SUCCEEDED, (s) -> { updateUI(); updateUI(); // start next service }); B .start(); }); B .setOnFailed((event) -> { A .addEventHandler(FAILED, (e) -> { doThat(); doThat(); updateUI(); updateUI(); }); }); • better error handling • lots of code! Executor-Thread FX-Thread

  36. 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! • good error handling • easy to read Executor-Thread FX-Thread

  37. Test service with fluent API

  38. 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

  39. 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

  40. OS X Menu Bar

  41. OS X Menu Bar • JavaFX is platform independent • no direct access to OS X application menu

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend