[8u40] Review request for RT-38855: DoubleProperty.doubleProperty() Javadoc needs small fix
Hi Kevin, Please review this simple javadoc fix: https://javafx-jira.kenai.com/browse/RT-38855 http://cr.openjdk.java.net/~vadim/RT-38855/webrev.00/ Thanks, Vadim
Re: How do I find out why the render loop is running?
Well, this was a pain in the ass. The cause is indeed ProgressBar/ProgressIndicator. It turns out that they can leak animations even when removed from the scene graph or their parents are made invisible. I filed: https://javafx-jira.kenai.com/browse/RT-38894 I now have a bunch of hacks to set the progress bar/indicators I have to non-indeterminate when they're no longer visible or just before they are removed from the scene graph, to let them clean up. I don't know why this is required because I can see the code is trying to do the right thing, but for whatever reason it does not seem to work reliably. I figured out what's running by taking a look at Toolkit.getToolkit().getMasterTimer().receivers every so often. A healthy (idling) app that isn't using up battery should have just a single entry inside a button click handler. If there are more, it means the app is animating even if nothing on the screen is changing.
Re: How do I find out why the render loop is running?
This is just a tip: until the bug is fixed, you can use a subclass of ProgressBar like the one below to avoid a bunch of hacks. class MyProgressBar extends ProgressBar { private final DoubleProperty myProgress = new SimpleDoubleProperty(); public DoubleProperty myProgressProperty() { return myProgress; } public void setMyProgress(double progress) { myProgress.set(progress); } public MyProgressBar() { progressProperty().bind( Bindings.when(Bindings.isNotNull(sceneProperty()).and(visibleProperty())) .then(myProgress) .otherwise(0); ); } } You will have to change setProgress() and progressProperty() in your code to setMyProgress() and myProgressProperty(). The good thing is that if you forget to replace setProgress() by setMyProgress(), you will get an error, because progressProperty() is now bound, so you cannot set() it. Hope this gets your code clarity close to the original level. Note, however, that this will not work if a parent is made invisible. You would need some more logic for that, unless there is an easy way to determine whether a node is actually visible. Here is one approach using EasyBind: public static BindingBoolean nodeVisible(Node node) { BindingBoolean parentVisible = EasyBind.monadic(node.parentProperty()) .flatMap(parent - nodeVisible(parent)) .orElse(true); return EasyBind.combine(parentVisible, node.visibleProperty(), (a, b) - a b); } Best, Tomas On Fri, Oct 3, 2014 at 10:37 PM, Mike Hearn m...@plan99.net wrote: Well, this was a pain in the ass. The cause is indeed ProgressBar/ProgressIndicator. It turns out that they can leak animations even when removed from the scene graph or their parents are made invisible. I filed: https://javafx-jira.kenai.com/browse/RT-38894 I now have a bunch of hacks to set the progress bar/indicators I have to non-indeterminate when they're no longer visible or just before they are removed from the scene graph, to let them clean up. I don't know why this is required because I can see the code is trying to do the right thing, but for whatever reason it does not seem to work reliably. I figured out what's running by taking a look at Toolkit.getToolkit().getMasterTimer().receivers every so often. A healthy (idling) app that isn't using up battery should have just a single entry inside a button click handler. If there are more, it means the app is animating even if nothing on the screen is changing.
Re: How do I find out why the render loop is running?
Can you add this workaround to the JIRA? Thanks. -- Kevin Tomas Mikula wrote: This is just a tip: until the bug is fixed, you can use a subclass of ProgressBar like the one below to avoid a bunch of hacks. class MyProgressBar extends ProgressBar { private final DoubleProperty myProgress = new SimpleDoubleProperty(); public DoubleProperty myProgressProperty() { return myProgress; } public void setMyProgress(double progress) { myProgress.set(progress); } public MyProgressBar() { progressProperty().bind( Bindings.when(Bindings.isNotNull(sceneProperty()).and(visibleProperty())) .then(myProgress) .otherwise(0); ); } } You will have to change setProgress() and progressProperty() in your code to setMyProgress() and myProgressProperty(). The good thing is that if you forget to replace setProgress() by setMyProgress(), you will get an error, because progressProperty() is now bound, so you cannot set() it. Hope this gets your code clarity close to the original level. Note, however, that this will not work if a parent is made invisible. You would need some more logic for that, unless there is an easy way to determine whether a node is actually visible. Here is one approach using EasyBind: public static BindingBoolean nodeVisible(Node node) { BindingBoolean parentVisible = EasyBind.monadic(node.parentProperty()) .flatMap(parent - nodeVisible(parent)) .orElse(true); return EasyBind.combine(parentVisible, node.visibleProperty(), (a, b) - a b); } Best, Tomas On Fri, Oct 3, 2014 at 10:37 PM, Mike Hearn m...@plan99.net wrote: Well, this was a pain in the ass. The cause is indeed ProgressBar/ProgressIndicator. It turns out that they can leak animations even when removed from the scene graph or their parents are made invisible. I filed: https://javafx-jira.kenai.com/browse/RT-38894 I now have a bunch of hacks to set the progress bar/indicators I have to non-indeterminate when they're no longer visible or just before they are removed from the scene graph, to let them clean up. I don't know why this is required because I can see the code is trying to do the right thing, but for whatever reason it does not seem to work reliably. I figured out what's running by taking a look at Toolkit.getToolkit().getMasterTimer().receivers every so often. A healthy (idling) app that isn't using up battery should have just a single entry inside a button click handler. If there are more, it means the app is animating even if nothing on the screen is changing.
Re: How do I find out why the render loop is running?
Okay :) So you are using opacityProperty() and not visibleProperty(), so my exact workaround would not work anyway. A nice thing about that kind of workaround though is that you would have the workaround in one place and once you remove it, the compiler points you to all other places you need to edit. But since the places you need to edit independently are exactly 2, it's not that bad :) Tomas On Sat, Oct 4, 2014 at 12:16 AM, Mike Hearn m...@plan99.net wrote: Oh well the hacks aren't so bad :-) Hack 1: animatedBind(loadingIndicatorArea, loadingIndicatorArea.opacityProperty(), when(isLoading).then(1.0).otherwise(0.0)); // Hack around a bug in jfx: progress indicator leaks the spinner animation even if it's invisible so we have // to forcibly end the animation here to avoid burning cpu. loadingIndicator.progressProperty().bind( when(loadingIndicatorArea.opacityProperty().greaterThan(0.0)).then(-1).otherwise(0) ); Hack 2: if (syncItem != null) { // Hack around JFX progress animator leak bug. GuiUtils.runOnGuiThreadAfter(500, () - { syncItem.cancel(); syncItem = null; }); } The runOnGuiThreadAfter() call can just be removed once the bug is resolved. No big deal. It was finding all the leaks that was the painful part, and figuring out what combination of things would make the animations stop. Finding the receivers array and figuring out how to trace the object graph back to the widgets causing them was the breakthrough.
Re: How do I find out why the render loop is running?
So you are using opacityProperty() and not visibleProperty(), so my exact workaround would not work anyway. I did originally put some code into animatedBind to set visible == false when opacity == 0.0 and vice versa, but it didn't seem to solve the animation leak so I took it out again. BTW animatedBind is a useful utility. It makes it much easier to make cool animations that adjust as the data model changes. Here it is: https://gist.github.com/mikehearn/f639176566d735b676e7 Something like that should be in the framework really.
Re: How do I find out why the render loop is running?
BTW animatedBind is a useful utility. It makes it much easier to make cool animations that adjust as the data model changes. Here it is: https://gist.github.com/mikehearn/f639176566d735b676e7 Something like that should be in the framework really. Nice indeed.