Use ScenePulseListener to avoid expensive recalculations?
Martin Sladecek
martin.sladecek at oracle.com
Thu Nov 7 06:34:51 PST 2013
On 11/07/2013 03:18 PM, Tomas Mikula wrote:
> Hi Martin,
>
> On Thu, Nov 7, 2013 at 2:32 PM, Martin Sladecek
> <martin.sladecek at oracle.com> wrote:
>> This is something different. When properties depends on each other (using
>> bindings), the binding computation is deferred to the first query (get()
>> call) of the dependant. That means, if q depends on p, you can call p.set()
>> as many times you want, but the recomputation will be triggered just before
>> first q.get() call.
> The point of my first example was inconsistency.
> Suppose this scenario (remember, the invalidation listeners of p are
> deferred until the next pulse):
>
> [pulse]
> ...
> p.set()
> ...
> q.get() // returned value not consistent with the value of p
> ...
> [pulse]
It is consistent, providing that you use binding API for the computation.
> I like my objects to appear consistent to the outside world at all
> times, so that the client code doesn't have to deal with the
> inconsistencies.
>
>> Also in your second example, the second invalidation of
>> s would be practically a no-op.
> It is not if you have an invalidation (or change) listener registered on s.
Only in case of change listener. Invalidation listener would not
validate/recompute s.
-Martin
>
> Tomas
>
>> Of course, this doesn't work if you have a ChangeListener on q, because the
>> ChangeListener basically need to do get() in order to compute the new
>> property value (which is passed as an argument to it's method).
>>
>> When it's not a property you want to recompute, but an internal state (you
>> use to setup the children), layoutChildren() should be the method for you.
>>
>> -Martin
>>
>>
>> On 11/07/2013 02:08 PM, Tomas Mikula wrote:
>>> On Thu, Nov 7, 2013 at 11:58 AM, John Hendrikx <hjohn at xs4all.nl> wrote:
>>>> Hm, I found it googling, and since it showed up here:
>>>>
>>>>
>>>> http://docs.oracle.com/javafx/2/api/javafx/scene/Scene.ScenePulseListener.html
>>>>
>>>> I figured it was public, but I just noticed the class is defined package
>>>> private.
>>> Although not part of the public API, you can use
>>>
>>> import com.sun.javafx.tk.TKPulseListener;
>>> import com.sun.javafx.tk.Toolkit;
>>>
>>> Toolkit.getToolkit().addSceneTkPulseListener(new
>>> TKPulseListener(){...})
>>>
>>>
>>> Anyway, I don't think deferring property invalidation until the next
>>> pulse is very useful in general, for the following reasons:
>>>
>>> 1) It can lead to inconsistent observable state of your objects.
>>> Consider an object with properties p, q, where the value of q depends
>>> on the value of p, and consider changing the value of p. Now, right
>>> after
>>> p.set(x);
>>> returns, the state of the object is inconsistent until the next pulse,
>>> and this inconsistency is observable to the outside world.
>>>
>>> 2) It doesn't (in general) avoid recalculations. Consider properties
>>> p, q, r, s, whose invalidation listeners are deferred until the next
>>> pulse, with bindings
>>> p <- q <- r <- s
>>> p <- s
>>> and consider changing the value of p in pulse 0. The invalidation
>>> listeners will fire as follows:
>>> pulse 1: p
>>> pulse 2: q, s
>>> pulse 3: r
>>> pulse 4: s
>>> As you see, the listeners of s are called twice, causing potentially
>>> expensive recalculation.
>>>
>>> For these reasons, I'm in favor of the approach suggested by Yennick,
>>> where you "commit" the properties yourself.
>>>
>>> Regards,
>>> Tomas
>>
More information about the openjfx-dev
mailing list