I’m in the process of converting to using the new animation system. There seem to be some things that weren’t implemented in the new system and I’m looking for reasonably elegant ways of achieving a similar result.
AnimControl class allowed listeners to be added to respond to events such as an animation being completed. I used this to move between random ‘waiting’ animations for inactive models. There doesn’t seem to be any similar system in
Is there a simple way of achieving this? I was considering adding a
Control that would check the time for the relevant layer and try to detect when it rolled over to zero. Is there a better way?
Ok I think I’ve worked this out - Instead of adding the
AnimClip directly to the composer I use a
Tween sequence with a
Tweens.callMethod after my clip that changes animation. I think that’s the intended method. If anyone familiar with this can confirm that’s the way to do it then I’ll close this thread.
I’d prefer to pass a
Runnable than use reflection but I guess I can just create my own
Tween that does exactly what I want rather than use
So often, listeners/Runnable would just end up calling another method anyway.
callMethod() is simpler and performs faster in those cases. (Performs equivalently in the “Runnable.run() does the work” case.)
Yep fair enough. Embedding a method name as a string does have the disadvantage that you can’t pick up errors at compile time and refactoring (e.g. renaming a method) becomes harder but I realise those are minor quibbles.
Actually might make sense in my case to just create a new extension of
AbstractTween that does the work of changing
AnimClip at the end of each loop.
Once I’ve got my head around the new animation system I’m happy to write some doc on it. There’s really nothing that I can see other than Nehon’s original post.
True. At least in this case it will fail during initialization rather than waiting until you try to run the method.
Do you have a reference for this? I’ve not been able to find any data so far.
This certainly looks like the type of thing that the JIT would optimize out very early…
A reference for what?
A cached Method.invoke() will perform the same as a method call. On the one hand, from a “microsecond” perspective, it’s technically one method calling another. On the other hand, it doesn’t have to do as many virtual method lookups because it’s often been preresolved.
People who think reflection is slow think that because of the lookups. Any sane developer, caches the Methods in advance (like in callMethod).
But the API could indeed have a Runnable or better Consumer interface, that way people could use java8’s Method references directly
I may have misunderstood you.
You said that a cached reflective method call would be faster than “a runnable that just calls another method.”
I assumed that anyone using an API that takes
runnable would, as @Darkchaos pointed out, pass a method reference directly.
I’ve not been able to find any statistics/tests comparing these approaches, and was wondering what happens when the optimizer gets through with them…
In the case of Runnable:
code calls Runnable.run()
Runnable.run() calls some method
In the case of Method:
code calls Method.invoke()
Method.invoke() calls some method
In theory, they are exactly the same. BUT the call to Method.invoke() can be more efficient than a call to “random object implementing Runnable”. And Method.invoke()'s call to “some method” is often more efficient than the run() calling “some method” because the virtual method has been cached already.
This is based only on theoretical understanding of the mechanisms involved. And in the end we are talking about times in the range of “method call overhead”… which is SUPER small. The smallest of the small.
The point is that people are afraid to use reflection thinking that it’s “inefficient”. But it’s just not the case. This is not even like a “C versus Java” debate that “depends on how you use it”. The performance difference between Method.invoke() and a direct method call is basically not measurable… not matter how you use it.
And where there is a microdifference, there is no predictable winner.
Thanks for the extra analysis. That does make sense, and clarifies where the conversation was coming from.
I had taken your original comment as “Prefer Reflection for performance reasons” when it appears you meant more “Performance is not a reason to avoid Reflection, if that’s what the API offers.”
I’m mostly interested because I find, post Java 8, several reasons that I would prefer to use lambda syntax or Method References when designing an API.
Yeah, I craved ‘method pointers’ since my C days… so I’m glad they finally added them.
Unfortunately, in my day job we only just recently moved up to Java 8 (last 2 years or so)… so I haven’t had a chance to internalize those features into my designs yet.