Class Choreographer
The choreographer receives timing pulses (such as vertical synchronization) from the render thread then schedules work to occur as part of rendering the next display frame.
Applications typically interact with the choreographer indirectly using higher level abstractions in the animation framework or the view hierarchy. Here are some examples of things you can do using the higher-level APIs.
- To post an animation to be processed on a regular time basis synchronized with
display frame rendering, use
ValueAnimator.start()
. - To post a
Runnable
to be invoked once at the beginning of the next display frame, useView.postOnAnimation(java.lang.Runnable)
. - To post a
Runnable
to be invoked once at the beginning of the next display frame after a delay, useView.postOnAnimationDelayed(java.lang.Runnable, long)
. - To post a call to
View.invalidate()
to occur once at the beginning of the next display frame, useView.postInvalidateOnAnimation()
. - To ensure that the contents of a
View
scroll smoothly and are drawn in sync with display frame rendering, do nothing. This already happens automatically.View.draw(Canvas)
will be called at the appropriate time.
However, there are a few cases where you might want to use the functions of the choreographer directly in your application. Here are some examples.
- If your application does its rendering in a different thread, possibly using GL,
or does not use the animation framework or view hierarchy at all
and you want to ensure that it is appropriately synchronized with the display, then use
postFrameCallback(icyllis.modernui.core.Choreographer.FrameCallback)
. - ... and that's about it.
Each Looper
thread has its own choreographer. Other threads can
post callbacks to run on the choreographer but they will run on the Looper
to which the choreographer belongs.
-
Nested Class Summary
Modifier and TypeClassDescriptionstatic interface
Implement this interface to receive a callback when a new display frame is being rendered. -
Field Summary
Modifier and TypeFieldDescriptionstatic final int
Callback type: Animation callback.static final int
Callback type: Commit callback.static final int
Callback type: Input callback.static final int
Callback type: Traversal callback. -
Method Summary
Modifier and TypeMethodDescriptionstatic long
The amount of time, in milliseconds, between each frame of the animation.long
Gets the time when the current frame started.long
Same asgetFrameTime()
but with nanosecond precision.static Choreographer
Gets the choreographer for the calling thread.long
LikegetFrameTimeNanos()
, but always returns the last frame time, not matter whether callbacks are currently running.void
postCallback
(int callbackType, Runnable action, Object token) Posts a callback to run on the next frame.void
postCallbackDelayed
(int callbackType, Runnable action, Object token, long delayMillis) Posts a callback to run on the next frame after the specified delay.void
postFrameCallback
(Choreographer.FrameCallback callback) Posts a frame callback to run on the next frame.void
postFrameCallbackDelayed
(Choreographer.FrameCallback callback, long delayMillis) Posts a frame callback to run on the next frame after the specified delay.void
removeCallbacks
(int callbackType, Runnable action, Object token) Removes callbacks that have the specified action and token.void
Removes a previously posted frame callback.static void
setFrameDelay
(long frameDelay) The amount of time, in milliseconds, between each frame of the animation.static long
subtractFrameDelay
(long delayMillis) Subtracts typical frame delay time from a delay interval in milliseconds.
-
Field Details
-
CALLBACK_INPUT
@Internal public static final int CALLBACK_INPUTCallback type: Input callback. Runs first.- See Also:
-
CALLBACK_ANIMATION
@Internal public static final int CALLBACK_ANIMATIONCallback type: Animation callback. Runs beforeCALLBACK_TRAVERSAL
.- See Also:
-
CALLBACK_TRAVERSAL
@Internal public static final int CALLBACK_TRAVERSALCallback type: Traversal callback. Handles layout and draw. Runs after all other asynchronous messages have been handled.- See Also:
-
CALLBACK_COMMIT
@Internal public static final int CALLBACK_COMMITCallback type: Commit callback. Handles post-draw operations for the frame. Runs after traversal completes. Theframe time
reported during this callback may be updated to reflect delays that occurred while traversals were in progress in case heavy layout operations caused some frames to be skipped. The frame time reported during this callback provides a better estimate of the start time of the frame in which animations (and other updates to the view hierarchy state) actually took effect.- See Also:
-
-
Method Details
-
getInstance
Gets the choreographer for the calling thread. Must be called from a thread that already has aLooper
associated with it. Must NOT be called from render thread.- Returns:
- The choreographer for this thread.
- Throws:
IllegalStateException
- if the thread does not have a looper
-
getFrameDelay
@Internal public static long getFrameDelay()The amount of time, in milliseconds, between each frame of the animation.This is a requested time that the animation will attempt to honor, but the actual delay between frames may be different, depending on system load and capabilities. This is a static function because the same delay will be applied to all animations, since they are all run off of a single timing loop.
- Returns:
- the requested time between frames, in milliseconds
-
setFrameDelay
@Internal public static void setFrameDelay(long frameDelay) The amount of time, in milliseconds, between each frame of the animation.This is a requested time that the animation will attempt to honor, but the actual delay between frames may be different, depending on system load and capabilities. This is a static function because the same delay will be applied to all animations, since they are all run off of a single timing loop.
- Parameters:
frameDelay
- the requested time between frames, in milliseconds
-
subtractFrameDelay
@Internal public static long subtractFrameDelay(long delayMillis) Subtracts typical frame delay time from a delay interval in milliseconds.This method can be used to compensate for animation delay times that have baked in assumptions about the frame delay. For example, it's quite common for code to assume a 60Hz frame time and bake in a 16ms delay. When we call
postCallbackDelayed(int, java.lang.Runnable, java.lang.Object, long)
on animation we want to know how long to wait before posting the animation callback but let the animation timer take care of the remaining frame delay time.This method is somewhat conservative about how much of the frame delay it subtracts. It uses the same value returned by
getFrameDelay()
which by default is 10ms even though many parts of the system assume 16ms. Consequently, we might still wait 6ms before posting an animation callback that we want to run on the next frame, but this is much better than waiting a whole 16ms and likely missing the deadline.- Parameters:
delayMillis
- The original delay time including an assumed frame delay.- Returns:
- The adjusted delay time with the assumed frame delay subtracted out.
-
postCallback
@Internal public void postCallback(int callbackType, @NonNull Runnable action, @Nullable Object token) Posts a callback to run on the next frame.The callback runs once then is automatically removed.
- Parameters:
callbackType
- The callback type.action
- The callback action to run during the next frame.token
- The callback token, or null if none.- See Also:
-
postCallbackDelayed
@Internal public void postCallbackDelayed(int callbackType, @NonNull Runnable action, @Nullable Object token, long delayMillis) Posts a callback to run on the next frame after the specified delay.The callback runs once then is automatically removed.
- Parameters:
callbackType
- The callback type.action
- The callback action to run during the next frame after the specified delay.token
- The callback token, or null if none.delayMillis
- The delay time in milliseconds.- See Also:
-
removeCallbacks
@Internal public void removeCallbacks(int callbackType, @Nullable Runnable action, @Nullable Object token) Removes callbacks that have the specified action and token.- Parameters:
callbackType
- The callback type.action
- The action property of the callbacks to remove, or null to remove callbacks with any action.token
- The token property of the callbacks to remove, or null to remove callbacks with any token.- See Also:
-
postFrameCallback
Posts a frame callback to run on the next frame.The callback runs once then is automatically removed.
- Parameters:
callback
- The frame callback to run during the next frame.- See Also:
-
postFrameCallbackDelayed
public void postFrameCallbackDelayed(@NonNull Choreographer.FrameCallback callback, long delayMillis) Posts a frame callback to run on the next frame after the specified delay.The callback runs once then is automatically removed.
- Parameters:
callback
- The frame callback to run during the next frame.delayMillis
- The delay time in milliseconds.- See Also:
-
removeFrameCallback
Removes a previously posted frame callback.- Parameters:
callback
- The frame callback to remove.- See Also:
-
getFrameTime
@Internal public long getFrameTime()Gets the time when the current frame started.This method provides the time in milliseconds when the frame started being rendered. The frame time provides a stable time base for synchronizing animations and drawing. It should be used instead of
Core.timeMillis()
orCore.timeNanos()
for animations and drawing in the UI. Using the frame time helps to reduce inter-frame jitter because the frame time is fixed at the time the frame was scheduled to start, regardless of when the animations or drawing callback actually runs. All callbacks that run as part of rendering a frame will observe the same frame time so using the frame time also helps to synchronize effects that are performed by different callbacks.Please note that the framework already takes care to process animations and drawing using the frame time as a stable time base. Most applications should not need to use the frame time information directly.
This method should only be called from within a callback.
- Returns:
- The frame start time, in the
Core.timeMillis()
time base. - Throws:
IllegalStateException
- if no frame is in progress.
-
getFrameTimeNanos
@Internal public long getFrameTimeNanos()Same asgetFrameTime()
but with nanosecond precision.- Returns:
- The frame start time, in the
Core.timeNanos()
time base. - Throws:
IllegalStateException
- if no frame is in progress.
-
getLastFrameTimeNanos
@Internal public long getLastFrameTimeNanos()LikegetFrameTimeNanos()
, but always returns the last frame time, not matter whether callbacks are currently running.- Returns:
- The frame start time of the last frame, in the
Core.timeNanos()
time base.
-