public abstract class WorkoutSession

  1. Object
  2. WorkoutSession

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.

Constructors

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

Methods

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

Inherited methods

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.