Package icyllis.modernui.core

# Class Choreographer

java.lang.Object
icyllis.modernui.core.Choreographer

@Internal public final class Choreographer extends Object
Coordinates the timing of animations, input and drawing.

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, use `View.postOnAnimation(java.lang.Runnable)`.
- To post a `Runnable` to be invoked once at the beginning of the next display frame after a delay, use `View.postOnAnimationDelayed(java.lang.Runnable, long)`.
- To post a call to `View.invalidate()` to occur once at the beginning of the next display frame, use `View.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

  Nested Classes
  Modifier and Type
  Class
  Description
  `static interface`
  `Choreographer.FrameCallback`
  Implement this interface to receive a callback when a new display frame is being rendered.

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `static final int`
  `CALLBACK_ANIMATION`
  Callback type: Animation callback.
  `static final int`
  `CALLBACK_COMMIT`
  Callback type: Commit callback.
  `static final int`
  `CALLBACK_INPUT`
  Callback type: Input callback.
  `static final int`
  `CALLBACK_TRAVERSAL`
  Callback type: Traversal callback.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static long`
  `getFrameDelay()`
  The amount of time, in milliseconds, between each frame of the animation.
  `long`
  `getFrameTime()`
  Gets the time when the current frame started.
  `long`
  `getFrameTimeNanos()`
  Same as `getFrameTime()` but with nanosecond precision.
  `static Choreographer`
  `getInstance()`
  Gets the choreographer for the calling thread.
  `long`
  `getLastFrameTimeNanos()`
  Like `getFrameTimeNanos()`, 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`
  `removeFrameCallback(Choreographer.FrameCallback callback)`
  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.

  ### Methods inherited from class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Field Details

  - ### CALLBACK_INPUT

    @Internal public static final int CALLBACK_INPUT
    Callback type: Input callback. Runs first.
    See Also:
      - Constant Field Values

  - ### CALLBACK_ANIMATION

    @Internal public static final int CALLBACK_ANIMATION
    Callback type: Animation callback. Runs before `CALLBACK_TRAVERSAL`.
    See Also:
      - Constant Field Values

  - ### CALLBACK_TRAVERSAL

    @Internal public static final int CALLBACK_TRAVERSAL
    Callback type: Traversal callback. Handles layout and draw. Runs after all other asynchronous messages have been handled.
    See Also:
      - Constant Field Values

  - ### CALLBACK_COMMIT

    @Internal public static final int CALLBACK_COMMIT
    Callback type: Commit callback. Handles post-draw operations for the frame. Runs after traversal completes. The `frame 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:
      - Constant Field Values

- ## Method Details

  - ### getInstance

    @NonNull public static Choreographer getInstance()
    Gets the choreographer for the calling thread. Must be called from a thread that already has a `Looper` 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:
      - `removeCallbacks(int, Runnable, Object)`

  - ### 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(int, Runnable, Object)`

  - ### 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:
      - `postCallback(int, java.lang.Runnable, java.lang.Object)`
      - `postCallbackDelayed(int, java.lang.Runnable, java.lang.Object, long)`

  - ### postFrameCallback

    public void postFrameCallback(@NonNull Choreographer.FrameCallback callback)
    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(icyllis.modernui.core.Choreographer.FrameCallback, long)`
      - `removeFrameCallback(icyllis.modernui.core.Choreographer.FrameCallback)`

  - ### 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:
      - `postFrameCallback(icyllis.modernui.core.Choreographer.FrameCallback)`
      - `removeFrameCallback(icyllis.modernui.core.Choreographer.FrameCallback)`

  - ### removeFrameCallback

    public void removeFrameCallback(@NonNull Choreographer.FrameCallback callback)
    Removes a previously posted frame callback.
    Parameters:
      `callback` - The frame callback to remove.
    See Also:
      - `postFrameCallback(icyllis.modernui.core.Choreographer.FrameCallback)`
      - `postFrameCallbackDelayed(icyllis.modernui.core.Choreographer.FrameCallback, long)`

  - ### 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()` or `Core.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 as `getFrameTime()` 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()
    Like `getFrameTimeNanos()`, 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.