# Class WorkoutSession

java.lang.Object
com.codename1.health.workout.WorkoutSession

public abstract class WorkoutSession extends Object

A workout being recorded.

Obtained from `WorkoutManager.startSession(WorkoutConfiguration)`. The state machine, the elapsed clock and the rollup of fed samples live here in shared code; ports implement only the `do*` methods.

##### Live and recorded sessions

`isLive()` tells you whether the operating system is running a real workout session -- keeping the app alive and collecting sensor data itself. It is false everywhere in this release: the only implementation here is a recorded session, and `WorkoutManager.isLiveSessionSupported()` says so on every platform. `HKWorkoutSession` on watchOS and iOS 26, and the Wear OS exercise client, are what would change that answer; nothing here drives them yet. Do not assume the OS keeps your app alive or collects data for you -- backgrounding can end the process and take the session with it.

On an Android phone it could not be live in any case, because Health Connect has no such concept: Google's documented approach there is to record the session yourself and write it when it ends, which is exactly what a recorded session does. So a recorded session is not a degraded shim -- it is the platform-correct design -- but it does mean nothing is collected unless you feed it, through `addSamples(List)` or by attaching a Bluetooth sensor with `SensorSessionOptions.setWorkoutSession(WorkoutSession)`.

Check `WorkoutManager.isSensorCollectionSupported()` before building UI that assumes a heart rate will appear on its own.

##### A killed workout is over

Sessions are deliberately not restored after the process dies. `end()` was never called, so nothing is written. An app that needs crash-resilient workouts should write partial records as it goes -- which is what the recorded path does anyway.

- ## Constructor Summary

  Constructors
  Modifier
  Constructor
  Description
  `protected`
  `WorkoutSession(WorkoutConfiguration configuration)`
  Ports and the framework construct sessions.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `final AsyncResource<Boolean>`
  `addEvent(WorkoutEvent event)`
  Records an event -- a lap, a marker, a segment boundary.
  `final void`
  `addListener(WorkoutSessionListener listener)`
  Registers a listener for state, statistics and events.
  `final AsyncResource<Boolean>`
  `addSamples(List<HealthSample> samples)`
  Feeds samples into the workout.
  `final void`
  `discard()`
  Abandons the workout without writing anything.
  `protected void`
  `doAddSamples(List<HealthSample> samples, AsyncResource<Boolean> out)`
  Hands fed samples to the platform.
  `protected abstract void`
  `doDiscard()`
  Abandons the workout without persisting.
  `protected abstract void`
  `doEnd(AsyncResource<WorkoutSample> out)`
  Stops collection and persists the workout.
  `protected abstract void`
  `doPause(AsyncResource<Boolean> out)`
  Pauses platform collection.
  `protected void`
  `doPrepare(AsyncResource<Boolean> out)`
  Warms up sensors.
  `protected abstract void`
  `doResume(AsyncResource<Boolean> out)`
  Resumes platform collection.
  `protected abstract void`
  `doStart(AsyncResource<Boolean> out)`
  Starts platform collection.
  `final AsyncResource<WorkoutSample>`
  `end()`
  Ends the workout and writes it to the health store, resolving with the persisted record.
  `protected final void`
  `fireEvent(WorkoutEvent event)`
  Notifies listeners of an event.
  `protected final void`
  `fireFailed(HealthException error)`
  Reports an unrecoverable failure and moves to `WorkoutSessionState.FAILED`.
  `protected final void`
  `fireStatisticsUpdated(HealthDataType type)`
  Notifies listeners that a statistic changed.
  `final WorkoutConfiguration`
  `getConfiguration()`
  The configuration this session was started with.
  `final long`
  `getElapsedMillis()`
  Time spent recording, excluding pauses.
  `final long`
  `getEndedAtMillis()`
  When it ended, epoch millis, or 0 while still running.
  `final List<WorkoutEvent>`
  `getEvents()`
  Every event recorded so far.
  `final long`
  `getStartedAtMillis()`
  When the workout started, epoch millis, or 0 before `start()`.
  `final WorkoutSessionState`
  `getState()`
  The current state.
  `final HealthQuantity`
  `getStatistic(HealthDataType type, AggregateMetric metric)`
  A live statistic, or `null` when the platform does not compute it and nothing has been fed in.
  `protected final Map<String, HealthQuantity>`
  `getStatisticsSnapshot()`
  The accumulated statistics, for ports assembling the final record.
  `boolean`
  `isLive()`
  Whether the operating system is running a real workout session -- see the class documentation.
  `final AsyncResource<Boolean>`
  `pause()`
  Pauses recording.
  `final AsyncResource<Boolean>`
  `prepare()`
  Warms up sensors ahead of `start()`, for apps that show a countdown.
  `final void`
  `removeListener(WorkoutSessionListener listener)`
  Removes a listener.
  `final AsyncResource<Boolean>`
  `resume()`
  Resumes after a pause.
  `protected final void`
  `setState(WorkoutSessionState newState)`
  Moves to a new state and notifies listeners.
  `final AsyncResource<Boolean>`
  `start()`
  Starts recording.

  ### Methods inherited from class Object

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

- ## Constructor Details

  - ### WorkoutSession

    protected WorkoutSession(WorkoutConfiguration configuration)
    Ports and the framework construct sessions.

- ## Method Details

  - ### getConfiguration

    public final WorkoutConfiguration getConfiguration()

    The configuration this session was started with.

    A copy, so that reconfiguring what this returns cannot change a workout already under way -- the same reason the session took a snapshot of what it was given. Without it the constructor's snapshot only moved the problem: `getConfiguration().setTitle(..)` reached the very instance `doEnd` reads when it persists.

  - ### getState

    public final WorkoutSessionState getState()
    The current state.

  - ### isLive

    public boolean isLive()
    Whether the operating system is running a real workout session -- see the class documentation. `false` means the clock and the saved record are real but collection is entirely up to you.

  - ### prepare

    public final AsyncResource<Boolean> prepare()
    Warms up sensors ahead of `start()`, for apps that show a countdown. Optional; `start()` works without it.

  - ### start

    public final AsyncResource<Boolean> start()
    Starts recording.

  - ### pause

    public final AsyncResource<Boolean> pause()
    Pauses recording. The elapsed clock stops.

  - ### resume

    public final AsyncResource<Boolean> resume()
    Resumes after a pause.

  - ### end

    public final AsyncResource<WorkoutSample> end()
    Ends the workout and writes it to the health store, resolving with the persisted record.

  - ### discard

    public final void discard()

    Abandons the workout without writing anything.

    A no-op once the workout has ended, and once `end()` has been called it is too late: the store write is already in flight, and claiming to have abandoned the session while that write lands -- then having its callback move the state back to `ENDED` -- would break the one promise in this method's name. Discard before ending, or delete the samples afterwards through the identifiers the write reports.

  - ### getElapsedMillis

    public final long getElapsedMillis()
    Time spent recording, excluding pauses.

  - ### getStartedAtMillis

    public final long getStartedAtMillis()
    When the workout started, epoch millis, or 0 before `start()`.

  - ### getEndedAtMillis

    public final long getEndedAtMillis()
    When it ended, epoch millis, or 0 while still running.

  - ### getStatistic

    public final HealthQuantity getStatistic(HealthDataType type, AggregateMetric metric)

    A live statistic, or `null` when the platform does not compute it and nothing has been fed in.

    Never fabricates a zero. On a recorded session with no sensor attached every statistic is null, and showing "0 bpm" instead would be a claim the app cannot support.

  - ### addSamples

    public final AsyncResource<Boolean> addSamples(List<HealthSample> samples)
    Feeds samples into the workout. On a recorded session this is the only way anything is collected.

  - ### addEvent

    public final AsyncResource<Boolean> addEvent(WorkoutEvent event)
    Records an event -- a lap, a marker, a segment boundary.

  - ### getEvents

    public final List<WorkoutEvent> getEvents()
    Every event recorded so far.

  - ### addListener

    public final void addListener(WorkoutSessionListener listener)
    Registers a listener for state, statistics and events.

  - ### removeListener

    public final void removeListener(WorkoutSessionListener listener)
    Removes a listener.

  - ### getStatisticsSnapshot

    protected final Map<String, HealthQuantity> getStatisticsSnapshot()
    The accumulated statistics, for ports assembling the final record.

  - ### doPrepare

    protected void doPrepare(AsyncResource<Boolean> out)
    Warms up sensors. Default completes immediately.

  - ### doStart

    protected abstract void doStart(AsyncResource<Boolean> out)
    Starts platform collection.

  - ### doPause

    protected abstract void doPause(AsyncResource<Boolean> out)
    Pauses platform collection.

  - ### doResume

    protected abstract void doResume(AsyncResource<Boolean> out)
    Resumes platform collection.

  - ### doEnd

    protected abstract void doEnd(AsyncResource<WorkoutSample> out)
    Stops collection and persists the workout.

  - ### doDiscard

    protected abstract void doDiscard()
    Abandons the workout without persisting.

  - ### doAddSamples

    protected void doAddSamples(List<HealthSample> samples, AsyncResource<Boolean> out)
    Hands fed samples to the platform. Default accepts them into the shared rollup only.

  - ### setState

    protected final void setState(WorkoutSessionState newState)
    Moves to a new state and notifies listeners. Ports call this for transitions the platform initiated.

  - ### fireStatisticsUpdated

    protected final void fireStatisticsUpdated(HealthDataType type)
    Notifies listeners that a statistic changed.

  - ### fireEvent

    protected final void fireEvent(WorkoutEvent event)
    Notifies listeners of an event.

  - ### fireFailed

    protected final void fireFailed(HealthException error)
    Reports an unrecoverable failure and moves to `WorkoutSessionState.FAILED`.