HealthConnectClient

public interface HealthConnectClient


Interface to access health and fitness records.

Summary

Nested types

public static class HealthConnectClient.Companion

Constants

default static final int

The Health Connect SDK APIs are available.

default static final int

The Health Connect SDK is unavailable on this device at the time.

default static final int

The Health Connect SDK APIs are currently unavailable, the provider is either not installed or needs to be updated.

Public methods

abstract @NonNull AggregationResult

Reads AggregateMetrics according to requested read criteria: Records from AggregateRequest.dataOriginFilter and within AggregateRequest.timeRangeFilter.

abstract @NonNull List<@NonNull AggregationResultGroupedByDuration>

Reads AggregateMetrics according to requested read criteria specified in AggregateGroupByDurationRequest.

abstract @NonNull List<@NonNull AggregationResultGroupedByPeriod>

Reads AggregateMetrics according to requested read criteria specified in AggregateGroupByPeriodRequest.

abstract void
deleteRecords(
    @NonNull KClass<@NonNull Record> recordType,
    @NonNull TimeRangeFilter timeRangeFilter
)

Deletes any Record of the given recordType in the given timeRangeFilter (automatically filtered to Record belonging to the calling application).

abstract void
deleteRecords(
    @NonNull KClass<@NonNull Record> recordType,
    @NonNull List<@NonNull String> recordIdsList,
    @NonNull List<@NonNull String> clientRecordIdsList
)

Deletes one or more Record by their identifiers.

abstract @NonNull ChangesResponse
getChanges(@NonNull String changesToken)

Retrieves changes in Android Health Platform, from a specific point in time represented by provided changesToken.

abstract @NonNull String

Retrieves a changes-token, representing a point in time in the underlying Android Health Platform for a given ChangesTokenRequest.

default static final @NonNull Intent
getHealthConnectManageDataIntent(
    @NonNull Context context,
    @NonNull String providerPackageName
)

Intent to open Health Connect data management screen on this phone.

default static final @NonNull String

Intent action to open Health Connect settings on this phone.

default static final @NonNull HealthConnectClient
getOrCreate(@NonNull Context context, @NonNull String providerPackageName)

Retrieves an IPC-backed HealthConnectClient instance binding to an available implementation.

abstract @NonNull PermissionController

Access operations related to permissions.

default static final int
getSdkStatus(@NonNull Context context, @NonNull String providerPackageName)

Determines whether the Health Connect SDK is available on this device at the moment.

abstract @NonNull InsertRecordsResponse

Inserts one or more Record and returns newly assigned androidx.health.connect.client.records.metadata.Metadata.id generated.

abstract @NonNull ReadRecordResponse<@NonNull T>
<T extends Record> readRecord(
    @NonNull KClass<@NonNull T> recordType,
    @NonNull String recordId
)

Reads one Record point with its recordType and recordId.

abstract @NonNull ReadRecordsResponse<@NonNull T>
<T extends Record> readRecords(@NonNull ReadRecordsRequest<@NonNull T> request)

Retrieves a collection of Records.

abstract void

Updates one or more Record of given UIDs to newly specified values.

Extension functions

default final void
<T extends Record> HealthConnectClientExt.deleteRecords(
    @NonNull HealthConnectClient receiver,
    @NonNull TimeRangeFilter timeRangeFilter
)

Deletes any Record of type T in the given timeRangeFilter (automatically filtered to Record belonging to the calling application).

default final void
<T extends Record> HealthConnectClientExt.deleteRecords(
    @NonNull HealthConnectClient receiver,
    @NonNull List<@NonNull String> recordIdsList,
    @NonNull List<@NonNull String> clientRecordIdsList
)

Deletes one or more Record by their identifiers.

default final @NonNull ReadRecordResponse<@NonNull T>
<T extends Record> HealthConnectClientExt.readRecord(
    @NonNull HealthConnectClient receiver,
    @NonNull String recordId
)

Reads one Record point of type T and with the specified recordId.

Constants

SDK_AVAILABLE

Added in 1.1.0-alpha07
default static final int SDK_AVAILABLE = 3

The Health Connect SDK APIs are available.

Apps can subsequently call getOrCreate to get an instance of HealthConnectClient.

SDK_UNAVAILABLE

Added in 1.1.0-alpha07
default static final int SDK_UNAVAILABLE = 1

The Health Connect SDK is unavailable on this device at the time. This can be due to the device running a lower than required Android Version.

Apps should hide any integration points to Health Connect in this case.

SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED

Added in 1.1.0-alpha07
default static final int SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED = 2

The Health Connect SDK APIs are currently unavailable, the provider is either not installed or needs to be updated.

Apps may choose to redirect to package installers to find a suitable APK.

Public methods

aggregate

abstract @NonNull AggregationResult aggregate(@NonNull AggregateRequest request)

Reads AggregateMetrics according to requested read criteria: Records from AggregateRequest.dataOriginFilter and within AggregateRequest.timeRangeFilter.

import androidx.health.connect.client.request.AggregateRequest

val response =
    healthConnectClient.aggregate(
        AggregateRequest(
            metrics = setOf(DistanceRecord.DISTANCE_TOTAL),
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )
// The result may be null if no data is available in the time range.
val distanceTotalInMeters = response[DistanceRecord.DISTANCE_TOTAL]?.inMeters

Example code to retrieve statistical aggregates like maximum or minimum heart rate:

import androidx.health.connect.client.request.AggregateRequest

val response =
    healthConnectClient.aggregate(
        AggregateRequest(
            setOf(HeartRateRecord.BPM_MAX, HeartRateRecord.BPM_MIN),
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )
// The result may be null if no data is available in the time range.
val minimumHeartRate = response[HeartRateRecord.BPM_MIN]
val maximumHeartRate = response[HeartRateRecord.BPM_MAX]
Parameters
@NonNull AggregateRequest request

AggregateRequest object specifying AggregateMetrics to aggregate and other filters.

Returns
@NonNull AggregationResult

the AggregationResult that contains aggregated values.

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Example code to aggregate cumulative data like distance:

aggregateGroupByDuration

abstract @NonNull List<@NonNull AggregationResultGroupedByDurationaggregateGroupByDuration(
    @NonNull AggregateGroupByDurationRequest request
)

Reads AggregateMetrics according to requested read criteria specified in AggregateGroupByDurationRequest.

This method is similar to aggregate but instead of returning one AggregationResult for the entire query's time interval, it returns a list of AggregationResultGroupedByDuration, with each row keyed by start and end time. For example: steps for today bucketed by hours.

An AggregationResultGroupedByDuration is returned only if there are Record to aggregate within start and end time of the row.

import androidx.health.connect.client.request.AggregateGroupByDurationRequest

val response =
    healthConnectClient.aggregateGroupByDuration(
        AggregateGroupByDurationRequest(
            metrics = setOf(StepsRecord.COUNT_TOTAL),
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
            timeRangeSlicer = Duration.ofMinutes(1)
        )
    )
for (monthlyResult in response) {
    // The result may be null if no data is available in the time range.
    val totalSteps = monthlyResult.result[StepsRecord.COUNT_TOTAL]
}
Parameters
@NonNull AggregateGroupByDurationRequest request

AggregateGroupByDurationRequest object specifying AggregateMetrics to aggregate and other filters.

Returns
@NonNull List<@NonNull AggregationResultGroupedByDuration>

a list of AggregationResultGroupedByDurations, each contains aggregated values and start/end time of the row. The list is sorted by time in ascending order.

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Example code to retrieve cumulative step count for each minute within provided time range:

aggregateGroupByPeriod

abstract @NonNull List<@NonNull AggregationResultGroupedByPeriodaggregateGroupByPeriod(@NonNull AggregateGroupByPeriodRequest request)

Reads AggregateMetrics according to requested read criteria specified in AggregateGroupByPeriodRequest.

This method is similar to aggregate but instead of returning one AggregationResult for the entire query's time interval, it returns a list of AggregationResultGroupedByPeriod, with each row keyed by start and end time. For example: steps for this month bucketed by day.

An AggregationResultGroupedByPeriod is returned only if there are Record to aggregate within start and end time of the row.

import androidx.health.connect.client.request.AggregateGroupByPeriodRequest

val response =
    healthConnectClient.aggregateGroupByPeriod(
        AggregateGroupByPeriodRequest(
            metrics = setOf(StepsRecord.COUNT_TOTAL),
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
            timeRangeSlicer = Period.ofMonths(1)
        )
    )
for (monthlyResult in response) {
    // The result may be null if no data is available in the time range.
    val totalSteps = monthlyResult.result[StepsRecord.COUNT_TOTAL]
}
Parameters
@NonNull AggregateGroupByPeriodRequest request

AggregateGroupByPeriodRequest object specifying AggregateMetrics to aggregate and other filters.

Returns
@NonNull List<@NonNull AggregationResultGroupedByPeriod>

a list of AggregationResultGroupedByPeriods, each contains aggregated values and start/end time of the row. The list is sorted by time in ascending order.

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Example code to retrieve cumulative step count for each month within provided time range:

deleteRecords

Added in 1.1.0-alpha07
abstract void deleteRecords(
    @NonNull KClass<@NonNull Record> recordType,
    @NonNull TimeRangeFilter timeRangeFilter
)

Deletes any Record of the given recordType in the given timeRangeFilter (automatically filtered to Record belonging to the calling application). Deletion of multiple Record is executed in a transaction - if one fails, none is deleted.

import androidx.health.connect.client.deleteRecords

healthConnectClient.deleteRecords<StepsRecord>(
    timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
Parameters
@NonNull KClass<@NonNull Record> recordType

Which type of Record to delete, such as Steps::class

@NonNull TimeRangeFilter timeRangeFilter

The TimeRangeFilter to delete from

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Example usage to delete written steps data in a time range:

deleteRecords

Added in 1.1.0-alpha07
abstract void deleteRecords(
    @NonNull KClass<@NonNull Record> recordType,
    @NonNull List<@NonNull String> recordIdsList,
    @NonNull List<@NonNull String> clientRecordIdsList
)

Deletes one or more Record by their identifiers. Deletion of multiple Record is executed in single transaction - if one fails, none is deleted.

import androidx.health.connect.client.deleteRecords

healthConnectClient.deleteRecords<StepsRecord>(
    recordIdsList = listOf(uid1, uid2),
    clientRecordIdsList = emptyList()
)
Parameters
@NonNull KClass<@NonNull Record> recordType

Which type of Record to delete, such as Steps::class

@NonNull List<@NonNull String> recordIdsList

List of androidx.health.connect.client.records.metadata.Metadata.id of Record to delete

@NonNull List<@NonNull String> clientRecordIdsList

List of client record IDs of Record to delete

Throws
android.os.RemoteException

For any IPC transportation failures. Deleting by invalid identifiers such as a non-existing identifier or deleting the same record multiple times will result in IPC failure.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Example usage to delete written steps data by its unique identifier:

getChanges

abstract @NonNull ChangesResponse getChanges(@NonNull String changesToken)

Retrieves changes in Android Health Platform, from a specific point in time represented by provided changesToken.

The response returned may not provide all the changes due to IPC or memory limits, see ChangesResponse.hasMore. Clients can make more api calls to fetch more changes from the Android Health Platform with updated ChangesResponse.nextChangesToken.

Provided changesToken may have expired if clients have not synced for extended period of time (such as a month). In this case ChangesResponse.changesTokenExpired will be set, and clients should generate a new changes-token via getChangesToken.

val response = client.getChanges(changesToken)
if (response.changesTokenExpired) {
// Consider re-sync and fetch new changes token.
} else {
// Process new insertion/deletions, either update local storage or upload to backends.
}
Parameters
@NonNull String changesToken

A Changes-Token that represents a specific point in time in Android Health Platform.

Returns
@NonNull ChangesResponse

a ChangesResponse with changes since provided changesToken.

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

See also
getChangesToken

getChangesToken

abstract @NonNull String getChangesToken(@NonNull ChangesTokenRequest request)

Retrieves a changes-token, representing a point in time in the underlying Android Health Platform for a given ChangesTokenRequest. Changes-tokens are used in getChanges to retrieve changes since that point in time.

Changes-tokens represent a point in time after which the client is interested in knowing the changes for a set of interested types of Record and optional DataOrigin filters.

Changes-tokens are only valid for 30 days after they're generated. Calls to getChanges with an expired changes-token will lead to ChangesResponse.changesTokenExpired

Parameters
@NonNull ChangesTokenRequest request

Includes interested types of record to observe changes and optional filters.

Returns
@NonNull String

a changes-token

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

See also
getChanges

getHealthConnectManageDataIntent

Added in 1.1.0-alpha07
default static final @NonNull Intent getHealthConnectManageDataIntent(
    @NonNull Context context,
    @NonNull String providerPackageName
)

Intent to open Health Connect data management screen on this phone. Developers should use this if they want to re-direct the user to Health Connect data management.

Parameters
@NonNull Context context

the context

@NonNull String providerPackageName

optional alternative package provider to choose for backend implementation

Returns
@NonNull Intent

Intent to open Health Connect data management screen.

getHealthConnectSettingsAction

Added in 1.1.0-alpha07
default static final @NonNull String getHealthConnectSettingsAction()

Intent action to open Health Connect settings on this phone. Developers should use this if they want to re-direct the user to Health Connect.

getOrCreate

Added in 1.1.0-alpha07
default static final @NonNull HealthConnectClient getOrCreate(@NonNull Context context, @NonNull String providerPackageName)

Retrieves an IPC-backed HealthConnectClient instance binding to an available implementation.

Parameters
@NonNull Context context

the context

@NonNull String providerPackageName

optional alternative package provider to choose for backend implementation

Returns
@NonNull HealthConnectClient

instance of HealthConnectClient ready for issuing requests

Throws
kotlin.UnsupportedOperationException

if service not available due to SDK version too low or running in a profile

kotlin.IllegalStateException

if the SDK is not available

See also
getSdkStatus

getPermissionController

Added in 1.1.0-alpha07
abstract @NonNull PermissionController getPermissionController()

Access operations related to permissions.

getSdkStatus

Added in 1.1.0-alpha07
default static final int getSdkStatus(@NonNull Context context, @NonNull String providerPackageName)

Determines whether the Health Connect SDK is available on this device at the moment.

import android.content.Intent

val availabilityStatus = HealthConnectClient.getSdkStatus(context, providerPackageName)
if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) {
    return // early return as there is no viable integration
}
if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) {
    // Optionally redirect to package installer to find a provider, for example:
    val uriString =
        "market://details?id=$providerPackageName&url=healthconnect%3A%2F%2Fonboarding"
    context.startActivity(
        Intent(Intent.ACTION_VIEW).apply {
            setPackage("com.android.vending")
            data = Uri.parse(uriString)
            putExtra("overlay", true)
            putExtra("callerId", context.packageName)
        }
    )
    return
}
val healthConnectClient = HealthConnectClient.getOrCreate(context)
// Issue operations with healthConnectClient
Parameters
@NonNull Context context

the context

@NonNull String providerPackageName

optional package provider to choose for backend implementation

insertRecords

abstract @NonNull InsertRecordsResponse insertRecords(@NonNull List<@NonNull Record> records)

Inserts one or more Record and returns newly assigned androidx.health.connect.client.records.metadata.Metadata.id generated. Insertion of multiple records is executed in a transaction - if one fails, none is inserted.

import androidx.health.connect.client.records.StepsRecord

val stepsRecord =
    StepsRecord(
        count = 120,
        startTime = START_TIME,
        endTime = END_TIME,
        startZoneOffset = START_ZONE_OFFSET,
        endZoneOffset = END_ZONE_OFFSET,
    )
healthConnectClient.insertRecords(listOf(stepsRecord))

To insert more complex data like nutrition for a user who’s eaten a banana:

import androidx.health.connect.client.records.NutritionRecord

val banana =
    NutritionRecord(
        name = "banana",
        energy = 105.0.kilocalories,
        dietaryFiber = 3.1.grams,
        potassium = 0.422.grams,
        totalCarbohydrate = 27.0.grams,
        totalFat = 0.4.grams,
        saturatedFat = 0.1.grams,
        sodium = 0.001.grams,
        sugar = 14.0.grams,
        vitaminB6 = 0.0005.grams,
        vitaminC = 0.0103.grams,
        startTime = START_TIME,
        endTime = END_TIME,
        startZoneOffset = START_ZONE_OFFSET,
        endZoneOffset = END_ZONE_OFFSET,
    )
healthConnectClient.insertRecords(listOf(banana))

To insert some heart rate data:

import androidx.health.connect.client.records.HeartRateRecord

val heartRateRecord =
    HeartRateRecord(
        startTime = START_TIME,
        startZoneOffset = START_ZONE_OFFSET,
        endTime = END_TIME,
        endZoneOffset = END_ZONE_OFFSET,
        // records 10 arbitrary data, to replace with actual data
        samples =
            List(10) { index ->
                HeartRateRecord.Sample(
                    time = START_TIME + Duration.ofSeconds(index.toLong()),
                    beatsPerMinute = 100 + index.toLong(),
                )
            },
    )
healthConnectClient.insertRecords(listOf(heartRateRecord))

androidx.health.connect.client.records.metadata.Metadata.clientRecordId can be used to deduplicate data with a client provided unique identifier. When a subsequent insertRecords is called with the same androidx.health.connect.client.records.metadata.Metadata.clientRecordId, whichever Record with the higher androidx.health.connect.client.records.metadata.Metadata.clientRecordVersion takes precedence.

Parameters
@NonNull List<@NonNull Record> records

List of records to insert

Returns
@NonNull InsertRecordsResponse

List of unique identifiers in the order of inserted records.

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

For example, to insert basic data like step counts:

readRecord

abstract @NonNull ReadRecordResponse<@NonNull T> <T extends Record> readRecord(
    @NonNull KClass<@NonNull T> recordType,
    @NonNull String recordId
)

Reads one Record point with its recordType and recordId.

Parameters
@NonNull KClass<@NonNull T> recordType

Which type of Record to read, such as Steps::class

@NonNull String recordId

androidx.health.connect.client.records.metadata.Metadata.id of Record to read

Returns
@NonNull ReadRecordResponse<@NonNull T>

The Record data point.

Throws
android.os.RemoteException

For any IPC transportation failures. Update with invalid identifiers will result in IPC failure.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

readRecords

abstract @NonNull ReadRecordsResponse<@NonNull T> <T extends Record> readRecords(@NonNull ReadRecordsRequest<@NonNull T> request)

Retrieves a collection of Records.

import androidx.health.connect.client.request.ReadRecordsRequest

val response =
    healthConnectClient.readRecords(
        ReadRecordsRequest<StepsRecord>(
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )
for (stepRecord in response.records) {
    // Process each step record
}
Parameters
<T extends Record>

the type of Record

@NonNull ReadRecordsRequest<@NonNull T> request

ReadRecordsRequest object specifying time range and other filters

Returns
@NonNull ReadRecordsResponse<@NonNull T>

a response containing a collection of Records.

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Example code to read basic data like step counts:

updateRecords

abstract void updateRecords(@NonNull List<@NonNull Record> records)

Updates one or more Record of given UIDs to newly specified values. Update of multiple records is executed in a transaction - if one fails, none is inserted.

Parameters
@NonNull List<@NonNull Record> records

List of records to update

Throws
android.os.RemoteException

For any IPC transportation failures. Update with invalid identifiers will result in IPC failure.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

Extension functions

HealthConnectClientExt.deleteRecords

default final void <T extends Record> HealthConnectClientExt.deleteRecords(
    @NonNull HealthConnectClient receiver,
    @NonNull TimeRangeFilter timeRangeFilter
)

Deletes any Record of type T in the given timeRangeFilter (automatically filtered to Record belonging to the calling application). Deletion of multiple Record is executed in a transaction - if one fails, none is deleted.

import androidx.health.connect.client.deleteRecords

healthConnectClient.deleteRecords<StepsRecord>(
    timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
Parameters
<T extends Record>

Which type of Record to delete, such as Steps.

@NonNull TimeRangeFilter timeRangeFilter

The TimeRangeFilter to delete from

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

kotlin.IllegalStateException

If service is not available.

See also
deleteRecords

Example usage to delete written steps data in a time range:

HealthConnectClientExt.deleteRecords

default final void <T extends Record> HealthConnectClientExt.deleteRecords(
    @NonNull HealthConnectClient receiver,
    @NonNull List<@NonNull String> recordIdsList,
    @NonNull List<@NonNull String> clientRecordIdsList
)

Deletes one or more Record by their identifiers. Deletion of multiple Record is executed in single transaction - if one fails, none is deleted.

import androidx.health.connect.client.deleteRecords

healthConnectClient.deleteRecords<StepsRecord>(
    recordIdsList = listOf(uid1, uid2),
    clientRecordIdsList = emptyList()
)
Parameters
<T extends Record>

Which type of Record to delete, such as Steps.

@NonNull List<@NonNull String> recordIdsList

List of androidx.health.connect.client.records.metadata.Metadata.id of Record to delete

@NonNull List<@NonNull String> clientRecordIdsList

List of client record IDs of Record to delete

Throws
android.os.RemoteException

For any IPC transportation failures. Deleting by invalid identifiers such as a non-existing identifier or deleting the same record multiple times will result in IPC failure.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

kotlin.IllegalStateException

If service is not available.

See also
deleteRecords

Example usage to delete written steps data by its unique identifier:

HealthConnectClientExt.readRecord

default final @NonNull ReadRecordResponse<@NonNull T> <T extends Record> HealthConnectClientExt.readRecord(
    @NonNull HealthConnectClient receiver,
    @NonNull String recordId
)

Reads one Record point of type T and with the specified recordId.

Parameters
<T extends Record>

Which type of Record to read, such as Steps.

@NonNull String recordId

androidx.health.connect.client.records.metadata.Metadata.id of Record to read

Returns
@NonNull ReadRecordResponse<@NonNull T>

The Record data point.

Throws
android.os.RemoteException

For any IPC transportation failures. Update with invalid identifiers will result in IPC failure.

java.lang.SecurityException

For requests with unpermitted access.

java.io.IOException

For any disk I/O issues.

kotlin.IllegalStateException

If service is not available.

See also
readRecord