HealthConnectClient


interface HealthConnectClient

Known direct subclasses
FakeHealthConnectClient

Fake HealthConnectClient to be used in tests for components that use it as a dependency.


Interface to access health and fitness records.

Summary

Constants

const Int

The Health Connect SDK APIs are available.

const Int

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

const Int

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

Public companion functions

Intent
getHealthConnectManageDataIntent(
    context: Context,
    providerPackageName: String
)

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

HealthConnectClient
getOrCreate(context: Context, providerPackageName: String)

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

Int
getSdkStatus(context: Context, providerPackageName: String)

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

Public companion properties

String

Intent action to open Health Connect settings on this phone.

Public functions

suspend AggregationResult

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

suspend List<AggregationResultGroupedByDuration>

Reads AggregateMetrics according to requested read criteria specified in AggregateGroupByDurationRequest.

suspend List<AggregationResultGroupedByPeriod>

Reads AggregateMetrics according to requested read criteria specified in AggregateGroupByPeriodRequest.

suspend Unit
deleteRecords(
    recordType: KClass<Record>,
    timeRangeFilter: TimeRangeFilter
)

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

suspend Unit
deleteRecords(
    recordType: KClass<Record>,
    recordIdsList: List<String>,
    clientRecordIdsList: List<String>
)

Deletes one or more Record by their identifiers.

suspend ChangesResponse
getChanges(changesToken: String)

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

suspend String

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

suspend InsertRecordsResponse

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

suspend ReadRecordResponse<T>
<T : Record> readRecord(recordType: KClass<T>, recordId: String)

Reads one Record point with its recordType and recordId.

suspend ReadRecordsResponse<T>
<T : Record> readRecords(request: ReadRecordsRequest<T>)

Retrieves a collection of Records.

suspend Unit

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

Public properties

open HealthConnectFeatures

Access operations related to feature availability.

PermissionController

Access operations related to permissions.

Extension functions

suspend inline Unit
<T : Record> HealthConnectClient.deleteRecords(
    timeRangeFilter: TimeRangeFilter
)

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

suspend inline Unit
<T : Record> HealthConnectClient.deleteRecords(
    recordIdsList: List<String>,
    clientRecordIdsList: List<String>
)

Deletes one or more Record by their identifiers.

suspend inline ReadRecordResponse<T>

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

Constants

SDK_AVAILABLE

Added in 1.1.0-alpha10
const val SDK_AVAILABLE = 3: Int

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-alpha10
const val SDK_UNAVAILABLE = 1: Int

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-alpha10
const val SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED = 2: Int

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 companion functions

getHealthConnectManageDataIntent

Added in 1.1.0-alpha10
fun getHealthConnectManageDataIntent(
    context: Context,
    providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME
): Intent

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
context: Context

the context

providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME

optional alternative package provider to choose for backend implementation

Returns
Intent

Intent to open Health Connect data management screen.

getOrCreate

Added in 1.1.0-alpha10
fun getOrCreate(
    context: Context,
    providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME
): HealthConnectClient

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

Parameters
context: Context

the context

providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME

optional alternative package provider to choose for backend implementation

Returns
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

getSdkStatus

Added in 1.1.0-alpha10
fun getSdkStatus(
    context: Context,
    providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME
): Int

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

import androidx.health.connect.client.HealthConnectClient

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
context: Context

the context

providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME

optional package provider to choose for backend implementation

Public companion properties

ACTION_HEALTH_CONNECT_SETTINGS

Added in 1.1.0-alpha10
val ACTION_HEALTH_CONNECT_SETTINGSString

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.

Public functions

aggregate

suspend fun aggregate(request: AggregateRequest): AggregationResult

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

import androidx.health.connect.client.records.DistanceRecord
import androidx.health.connect.client.request.AggregateRequest
import androidx.health.connect.client.time.TimeRangeFilter

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.records.HeartRateRecord
import androidx.health.connect.client.request.AggregateRequest
import androidx.health.connect.client.time.TimeRangeFilter

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
request: AggregateRequest

AggregateRequest object specifying AggregateMetrics to aggregate and other filters.

Returns
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

suspend fun aggregateGroupByDuration(request: AggregateGroupByDurationRequest): List<AggregationResultGroupedByDuration>

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.records.StepsRecord
import androidx.health.connect.client.request.AggregateGroupByDurationRequest
import androidx.health.connect.client.time.TimeRangeFilter

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
request: AggregateGroupByDurationRequest

AggregateGroupByDurationRequest object specifying AggregateMetrics to aggregate and other filters.

Returns
List<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

suspend fun aggregateGroupByPeriod(request: AggregateGroupByPeriodRequest): List<AggregationResultGroupedByPeriod>

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.records.StepsRecord
import androidx.health.connect.client.request.AggregateGroupByPeriodRequest
import androidx.health.connect.client.time.TimeRangeFilter

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
request: AggregateGroupByPeriodRequest

AggregateGroupByPeriodRequest object specifying AggregateMetrics to aggregate and other filters.

Returns
List<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-alpha10
suspend fun deleteRecords(
    recordType: KClass<Record>,
    timeRangeFilter: TimeRangeFilter
): Unit

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
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.time.TimeRangeFilter

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

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

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-alpha10
suspend fun deleteRecords(
    recordType: KClass<Record>,
    recordIdsList: List<String>,
    clientRecordIdsList: List<String>
): Unit

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
import androidx.health.connect.client.records.StepsRecord

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

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

recordIdsList: List<String>

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

clientRecordIdsList: List<String>

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

suspend fun getChanges(changesToken: String): ChangesResponse

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
changesToken: String

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

Returns
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

suspend fun getChangesToken(request: ChangesTokenRequest): String

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
request: ChangesTokenRequest

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

Returns
String

a changes-token

Throws
android.os.RemoteException

For any IPC transportation failures.

java.lang.SecurityException

For requests with unpermitted access.

See also
getChanges

insertRecords

suspend fun insertRecords(records: List<Record>): InsertRecordsResponse

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
import androidx.health.connect.client.units.grams
import androidx.health.connect.client.units.kilocalories

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
records: List<Record>

List of records to insert

Returns
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

suspend fun <T : Record> readRecord(recordType: KClass<T>, recordId: String): ReadRecordResponse<T>

Reads one Record point with its recordType and recordId.

Parameters
recordType: KClass<T>

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

recordId: String

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

Returns
ReadRecordResponse<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

suspend fun <T : Record> readRecords(request: ReadRecordsRequest<T>): ReadRecordsResponse<T>

Retrieves a collection of Records.

import androidx.health.connect.client.readRecord
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.request.ReadRecordsRequest
import androidx.health.connect.client.time.TimeRangeFilter

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

the type of Record

request: ReadRecordsRequest<T>

ReadRecordsRequest object specifying time range and other filters

Returns
ReadRecordsResponse<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

suspend fun updateRecords(records: List<Record>): Unit

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
records: List<Record>

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.

Public properties

features

Added in 1.1.0-alpha10
@ExperimentalFeatureAvailabilityApi
open val featuresHealthConnectFeatures

Access operations related to feature availability.

permissionController

Added in 1.1.0-alpha10
val permissionControllerPermissionController

Access operations related to permissions.

Extension functions

suspend inline fun <T : Record> HealthConnectClient.deleteRecords(
    timeRangeFilter: TimeRangeFilter
): Unit

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
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.time.TimeRangeFilter

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

Which type of Record to delete, such as Steps.

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:

suspend inline fun <T : Record> HealthConnectClient.deleteRecords(
    recordIdsList: List<String>,
    clientRecordIdsList: List<String>
): Unit

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
import androidx.health.connect.client.records.StepsRecord

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

Which type of Record to delete, such as Steps.

recordIdsList: List<String>

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

clientRecordIdsList: List<String>

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:

suspend inline fun <T : Record> HealthConnectClient.readRecord(recordId: String): ReadRecordResponse<T>

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

Parameters
<T : Record>

Which type of Record to read, such as Steps.

recordId: String

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

Returns
ReadRecordResponse<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