HealthConnectClient
public interface HealthConnectClient
FakeHealthConnectClient |
Fake |
Interface to access health and fitness records.
Summary
Nested types |
|---|
public static class HealthConnectClient.Companion |
Constants |
|
|---|---|
default static final int |
SDK_AVAILABLE = 3The Health Connect SDK APIs are available. |
default static final int |
SDK_UNAVAILABLE = 1The 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. |
Extension functions |
|
|---|---|
default final void |
<T extends Record> HealthConnectClientExt.deleteRecords(Deletes any |
default final void |
<T extends Record> HealthConnectClientExt.deleteRecords(Deletes one or more |
default final @NonNull ReadRecordResponse<@NonNull T> |
<T extends Record> HealthConnectClientExt.readRecord(Reads one |
Constants
SDK_AVAILABLE
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
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
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.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 | |
|---|---|
@NonNull AggregateRequest request |
|
| Returns | |
|---|---|
@NonNull AggregationResult |
the |
| 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 AggregationResultGroupedByDuration> aggregateGroupByDuration(
@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.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 | |
|---|---|
@NonNull AggregateGroupByDurationRequest request |
|
| Returns | |
|---|---|
@NonNull List<@NonNull AggregationResultGroupedByDuration> |
a list of |
| 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 AggregationResultGroupedByPeriod> aggregateGroupByPeriod(@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.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 | |
|---|---|
@NonNull AggregateGroupByPeriodRequest request |
|
| Returns | |
|---|---|
@NonNull List<@NonNull AggregationResultGroupedByPeriod> |
a list of |
| 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: |
createMedicalDataSource
@ExperimentalPersonalHealthRecordApi
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
default @NonNull MedicalDataSource createMedicalDataSource(@NonNull CreateMedicalDataSourceRequest request)
Creates a MedicalDataSource using a CreateMedicalDataSourceRequest.
Regarding permissions:
-
Caller must hold
PERMISSION_WRITE_MEDICAL_DATAin order to call this API, otherwise aSecurityExceptionwill be thrown. -
With
PERMISSION_WRITE_MEDICAL_DATAgranted, caller is permitted to call this API in either foreground or background.
Medical data is represented using the Fast Healthcare Interoperability Resources (FHIR) standard.
A MedicalDataSource needs to be created before any MedicalResources for that source can be inserted. Separate MedicalDataSources should be created for medical records coming from different sources (e.g. different FHIR endpoints, different healthcare systems), unless the data has been reconciled and all records have a unique combination of resource type and resource id.
The CreateMedicalDataSourceRequest.displayName must be unique across all medical data sources created by an app, otherwise an IllegalArgumentException will be thrown. See CreateMedicalDataSourceRequest.fhirBaseUri for more details on the FHIR base URI. The data source can not be updated after creation.
This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE import androidx.health.connect.client.records.FhirVersion import androidx.health.connect.client.records.MedicalDataSource import androidx.health.connect.client.request.CreateMedicalDataSourceRequest // Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis if ( healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) != FEATURE_STATUS_AVAILABLE ) { return } // Create a `MedicalDataSource` // Note that `displayName` must be unique across `MedicalDataSource`s val medicalDataSource: MedicalDataSource = healthConnectClient.createMedicalDataSource( CreateMedicalDataSourceRequest( fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"), displayName = "Test Data Source", fhirVersion = FhirVersion(4, 0, 1), ) )
| Parameters | |
|---|---|
@NonNull CreateMedicalDataSourceRequest request |
request containing details of the |
| Returns | |
|---|---|
@NonNull MedicalDataSource |
the created |
| Throws | |
|---|---|
java.lang.SecurityException |
if caller does not hold |
deleteMedicalDataSourceWithData
@ExperimentalPersonalHealthRecordApi
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
default void deleteMedicalDataSourceWithData(@NonNull String id)
Deletes a MedicalDataSource and all data contained within it.
Regarding permissions:
-
Caller must hold
PERMISSION_WRITE_MEDICAL_DATAin order to call this API, otherwise aSecurityExceptionwill be thrown. -
With
PERMISSION_WRITE_MEDICAL_DATAgranted, caller is permitted to call this API in either foreground or background. -
Caller may only delete data sources it created.
Medical data is represented using the Fast Healthcare Interoperability Resources (FHIR) standard.
This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE import androidx.health.connect.client.records.FhirVersion import androidx.health.connect.client.records.MedicalDataSource import androidx.health.connect.client.request.CreateMedicalDataSourceRequest // Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis if ( healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) != FEATURE_STATUS_AVAILABLE ) { return } // Get or creates a `MedicalDataSource` // Each `MedicalDataSource` is assigned an `id` by the system on creation val medicalDataSource: MedicalDataSource = healthConnectClient.createMedicalDataSource( CreateMedicalDataSourceRequest( fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"), displayName = "Test Data Source", fhirVersion = FhirVersion(4, 0, 1), ) ) // Delete the `MedicalDataSource` that has the specified `id` healthConnectClient.deleteMedicalDataSourceWithData(medicalDataSource.id)
| Throws | |
|---|---|
kotlin.IllegalArgumentException |
if |
deleteMedicalResources
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
@ExperimentalPersonalHealthRecordApi
default void deleteMedicalResources(@NonNull List<@NonNull MedicalResourceId> ids)
Deletes a list of MedicalResources by the provided list of MedicalResourceIds.
-
If any ID in
idsis invalid, the API will throw anIllegalArgumentException, and nothing will be deleted. -
If any ID in
idsdoes not exist, that ID will be ignored, while deletion on other IDs will be performed.
Regarding permissions:
-
Caller must hold
PERMISSION_WRITE_MEDICAL_DATAin order to call this API, even then, it can only delete its own data. If any of the items inidsbelongs to another app, they will be ignored. -
Deletes are permitted in the foreground or background.
This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE import androidx.health.connect.client.records.FhirVersion import androidx.health.connect.client.records.MedicalDataSource import androidx.health.connect.client.records.MedicalResource import androidx.health.connect.client.records.MedicalResourceId import androidx.health.connect.client.request.CreateMedicalDataSourceRequest import androidx.health.connect.client.request.UpsertMedicalResourceRequest // Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis if ( healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) != FEATURE_STATUS_AVAILABLE ) { return } // Get or create a `MedicalDataSource` val medicalDataSource: MedicalDataSource = healthConnectClient.createMedicalDataSource( CreateMedicalDataSourceRequest( fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"), displayName = "Test Data Source", fhirVersion = FhirVersion(4, 0, 1), ) ) // Insert `MedicalResource`s into the `MedicalDataSource` val medicalResources: List<MedicalResource> = healthConnectClient.upsertMedicalResources( listOf( UpsertMedicalResourceRequest( medicalDataSource.id, medicalDataSource.fhirVersion, medicationJsonToInsert, // a valid FHIR json string ) ) ) // Delete `MedicalResource`s matching the specified `dataSourceId`, `type` and `fhirResourceId` healthConnectClient.deleteMedicalResources( medicalResources.map { medicalResource: MedicalResource -> MedicalResourceId( dataSourceId = medicalDataSource.id, fhirResourceType = medicalResource.id.fhirResourceType, fhirResourceId = medicalResource.id.fhirResourceId, ) } )
| Parameters | |
|---|---|
@NonNull List<@NonNull MedicalResourceId> ids |
The ids to delete. |
| Throws | |
|---|---|
java.lang.SecurityException |
if caller does not hold |
deleteMedicalResources
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
@ExperimentalPersonalHealthRecordApi
default void deleteMedicalResources(@NonNull DeleteMedicalResourcesRequest request)
Deletes MedicalResources based on given filters in request.
Only MedicalResources inserted by the calling app will be deleted. If the request matches any other MedicalResources, these will be ignored.
Regarding permissions:
-
Caller must hold
PERMISSION_WRITE_MEDICAL_DATAin order to call this API. -
Deletes are permitted in the foreground or background.
This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE import androidx.health.connect.client.records.FhirVersion import androidx.health.connect.client.records.MedicalDataSource import androidx.health.connect.client.records.MedicalResource import androidx.health.connect.client.records.MedicalResource.Companion.MEDICAL_RESOURCE_TYPE_MEDICATIONS import androidx.health.connect.client.request.CreateMedicalDataSourceRequest import androidx.health.connect.client.request.DeleteMedicalResourcesRequest import androidx.health.connect.client.request.UpsertMedicalResourceRequest // Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis if ( healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) != FEATURE_STATUS_AVAILABLE ) { return } // Get or create a `MedicalDataSource` val medicalDataSource: MedicalDataSource = healthConnectClient.createMedicalDataSource( CreateMedicalDataSourceRequest( fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"), displayName = "Test Data Source", fhirVersion = FhirVersion(4, 0, 1), ) ) // Insert `MedicalResource`s into the `MedicalDataSource` val medicalResources: List<MedicalResource> = healthConnectClient.upsertMedicalResources( listOf( UpsertMedicalResourceRequest( medicalDataSource.id, medicalDataSource.fhirVersion, medicationJsonToInsert, // a valid FHIR json string ) ) ) // Delete all `MedicalResource`s that are in any pair of provided `dataSourceIds` and // `medicalResourceTypes` healthConnectClient.deleteMedicalResources( DeleteMedicalResourcesRequest( dataSourceIds = setOf(medicalDataSource.id), medicalResourceTypes = setOf(MEDICAL_RESOURCE_TYPE_MEDICATIONS), ) )
| Parameters | |
|---|---|
@NonNull DeleteMedicalResourcesRequest request |
The request that contains the filters to delete. |
| Throws | |
|---|---|
java.lang.SecurityException |
if caller does not hold |
deleteRecords
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 import androidx.health.connect.client.records.StepsRecord import androidx.health.connect.client.time.TimeRangeFilter healthConnectClient.deleteRecords<StepsRecord>( timeRangeFilter = TimeRangeFilter.between(startTime, endTime) )
| Parameters | |
|---|---|
@NonNull KClass<@NonNull Record> recordType |
Which type of |
@NonNull TimeRangeFilter timeRangeFilter |
The |
| 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
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 import androidx.health.connect.client.records.StepsRecord healthConnectClient.deleteRecords<StepsRecord>( recordIdsList = listOf(uid1, uid2), clientRecordIdsList = emptyList(), )
| Parameters | |
|---|---|
@NonNull KClass<@NonNull Record> recordType |
Which type of |
@NonNull List<@NonNull String> recordIdsList |
List of |
@NonNull List<@NonNull String> clientRecordIdsList |
List of client record IDs of |
| 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 Health Connect, 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 Health Connect 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 |
| 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. |
| Throws | |
|---|---|
android.os.RemoteException |
For any IPC transportation failures. |
java.lang.SecurityException |
For requests with unpermitted access. |
| See also | |
|---|---|
getChanges |
getFeatures
default @NonNull HealthConnectFeatures getFeatures()
Access operations related to feature availability.
getHealthConnectManageDataIntent
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.
getHealthConnectSettingsAction
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.
getMedicalDataSources
@ExperimentalPersonalHealthRecordApi
default @NonNull List<@NonNull MedicalDataSource> getMedicalDataSources(@NonNull List<@NonNull String> ids)
Gets MedicalDataSources for the provided list of ids.
The returned list of data sources will be in the same order as the ids.
Number of data sources returned by this API will depend based on below factors:
-
If an empty list of
idsis provided, no data sources will be returned. -
If an id is invalid or non-existent, no data source will be returned for that id, this means the returned list might have fewer elements than
ids. -
Callers will only get data sources they are permitted to get. See below.
There is no specific read permission for getting data sources. Instead, permission to read data sources is based on whether the caller has permission to read the data currently contained in that data source. Being permitted to get data sources is dependent on the following logic, in priority order, earlier statements take precedence.
-
A caller without any read medical permissions such as
PERMISSION_READ_MEDICAL_DATA_VACCINESor the write permissionPERMISSION_WRITE_MEDICAL_DATAis not permitted get anyMedicalDataSources, including ones that it created. -
A caller with the write permission is permitted to read its own
MedicalDataSources regardless whether it's in foreground or background. -
A caller with only a read permission, when in background, is only permitted to read its own
MedicalDataSources that contains at least oneMedicalResourcewith the type that the read permission covers. However, when the caller is in foreground or if it holdsPERMISSION_READ_HEALTH_DATA_IN_BACKGROUND, it can also read other apps'MedicalDataSources as long as each of thoseMedicalDataSourcecontains at least oneMedicalResourcewith the corresponding type. -
For example, if a caller
Acreated aMedicalDataSourceDS1, then usedDS1to insert aMedicalResourceMR1with typeMedicalResource.MEDICAL_RESOURCE_TYPE_VACCINES, and another callerBcreatedDS2. IfAholdsPERMISSION_READ_MEDICAL_DATA_VACCINES, it can only readDS1in background. However, if it is in foreground or holdsPERMISSION_READ_HEALTH_DATA_IN_BACKGROUND, it can read bothDS1andDS2.
This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE import androidx.health.connect.client.records.FhirVersion import androidx.health.connect.client.records.MedicalDataSource import androidx.health.connect.client.request.CreateMedicalDataSourceRequest // Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis if ( healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) != FEATURE_STATUS_AVAILABLE ) { return } // Get or create a `MedicalDataSource` // Each `MedicalDataSource` is assigned an `id` by the system on creation val medicalDataSource: MedicalDataSource = healthConnectClient.createMedicalDataSource( CreateMedicalDataSourceRequest( fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"), displayName = "Test Data Source", fhirVersion = FhirVersion(4, 0, 1), ) ) // Retrieve all `MedicalDataSource` with `id` matching any of the given ids val medicalDataSources: List<MedicalDataSource> = healthConnectClient.getMedicalDataSources(listOf(medicalDataSource.id, anotherId))
| Parameters | |
|---|---|
@NonNull List<@NonNull String> ids |
ids of the |
| Returns | |
|---|---|
@NonNull List<@NonNull MedicalDataSource> |
|
getMedicalDataSources
@ExperimentalPersonalHealthRecordApi
default @NonNull List<@NonNull MedicalDataSource> getMedicalDataSources(@NonNull GetMedicalDataSourcesRequest request)
Gets the requested MedicalDataSources using GetMedicalDataSourcesRequest. Number of data sources returned by this API will depend based on below factors:
-
If an empty
GetMedicalDataSourcesRequestis passed, all data sources for all apps are requested, and all which the caller is permitted to get will be returned. See below. -
If
GetMedicalDataSourcesRequest.packageNamesis not empty, then only the data sources created by those packages is being requested. All data sources created by those packages which the caller is permitted to get will be returned. See below.
There is no specific read permission for getting data sources. Instead, permission to read data sources is based on whether the caller has permission to read the data currently contained in that data source. Specifically:
-
A caller without any read medical permissions such as
PERMISSION_READ_MEDICAL_DATA_VACCINESor the write permissionPERMISSION_WRITE_MEDICAL_DATAis not permitted get anyMedicalDataSources, including ones that it created. -
A caller with the write permission is permitted to read its own
MedicalDataSources regardless whether it's in foreground or background. -
A caller with only a read permission, when in background, is only permitted to read its own
MedicalDataSources that contains at least oneMedicalResourcewith the type that the read permission covers. However, when the caller is in foreground or if it holdsPERMISSION_READ_HEALTH_DATA_IN_BACKGROUND, it can also read other apps'MedicalDataSources as long as each of thoseMedicalDataSourcecontains at least oneMedicalResourcewith the corresponding type. -
For example, a client
Acreated aMedicalDataSourceDS1, then usedDS1to insert aMedicalResourceMR1with typeMedicalResource.MEDICAL_RESOURCE_TYPE_VACCINES. Similarly another clientBcreatedDS2, then usedDS2to insert anotherMedicalResourceMR2with the sameMedicalResource.MEDICAL_RESOURCE_TYPE_VACCINES. IfAholdsPERMISSION_READ_MEDICAL_DATA_VACCINESand it is in background, it can only readDS1. However, ifAis in foreground or holdsPERMISSION_READ_HEALTH_DATA_IN_BACKGROUND, it can read bothDS1andDS2.
This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE import androidx.health.connect.client.records.FhirVersion import androidx.health.connect.client.records.MedicalDataSource import androidx.health.connect.client.request.CreateMedicalDataSourceRequest import androidx.health.connect.client.request.GetMedicalDataSourcesRequest // Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis if ( healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) != FEATURE_STATUS_AVAILABLE ) { return } // Get or create a `MedicalDataSource` // Each `MedicalDataSource` contains the `packageName` which created it val medicalDataSource: MedicalDataSource = healthConnectClient.createMedicalDataSource( CreateMedicalDataSourceRequest( fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"), displayName = "Test Data Source", fhirVersion = FhirVersion(4, 0, 1), ) ) // Retrieve all `MedicalDataSource`s created by any of the specified package names // Package names may be found in other `MedicalDataSource`s or from arbitrary input val medicalDataSources: List<MedicalDataSource> = healthConnectClient.getMedicalDataSources( GetMedicalDataSourcesRequest(listOf(medicalDataSource.packageName, anotherPackageName)) )
| Parameters | |
|---|---|
@NonNull GetMedicalDataSourcesRequest request |
containing details of the |
| Returns | |
|---|---|
@NonNull List<@NonNull MedicalDataSource> |
|
getOrCreate
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 |
| 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
abstract @NonNull PermissionController getPermissionController()
Access operations related to permissions.
getSdkStatus
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 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 | |
|---|---|
@NonNull Context context |
the context |
@NonNull String providerPackageName |
optional package provider to choose for backend implementation |
| Returns | |
|---|---|
int |
One of |
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 import androidx.health.connect.client.records.metadata.Metadata val stepsRecord = StepsRecord( count = 120, startTime = START_TIME, endTime = END_TIME, startZoneOffset = START_ZONE_OFFSET, endZoneOffset = END_ZONE_OFFSET, metadata = Metadata.manualEntry(), ) 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.records.metadata.Metadata 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, metadata = Metadata.manualEntry(), ) healthConnectClient.insertRecords(listOf(banana))
To insert some heart rate data:
import androidx.health.connect.client.records.HeartRateRecord import androidx.health.connect.client.records.metadata.Metadata val heartRateRecord = HeartRateRecord( startTime = START_TIME, startZoneOffset = START_ZONE_OFFSET, endTime = END_TIME, endZoneOffset = END_ZONE_OFFSET, metadata = Metadata.manualEntry(), // 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.
| 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: |
readMedicalResources
@ExperimentalPersonalHealthRecordApi
default @NonNull List<@NonNull MedicalResource> readMedicalResources(@NonNull List<@NonNull MedicalResourceId> ids)
Reads a collection of MedicalResources given a list of MedicalResourceIds.
The number and order of medical resources returned by this API is not guaranteed, depending on a number of factors:
-
If an empty list of IDs is provided, an empty list will be returned.
-
If any ID does not exist, no medical resource will be returned for that ID.
-
Only permitted
MedicalResources are returned. Specifically: -
A caller without any read medical permissions such as
PERMISSION_READ_MEDICAL_DATA_VACCINES, or the write medical permissionPERMISSION_WRITE_MEDICAL_DATAis not permitted to read anyMedicalResource, including ones that it created. -
A caller with the write permission is permitted to read its own
MedicalResources of any type regardless whether it's in foreground or background. -
A caller with only a read permission, when in background, is only permitted to read its own
MedicalResources of the corresponding type. For example, if a caller only holdsPERMISSION_READ_MEDICAL_DATA_VACCINES, then when in background it is only permitted to read its ownMedicalResources withMedicalResource.MEDICAL_RESOURCE_TYPE_VACCINES. However, when it is in foreground or if it holdsPERMISSION_READ_HEALTH_DATA_IN_BACKGROUND, it is permitted to read all vaccinesMedicalResources, including ones that were written by other apps.
Each returned MedicalResource is not guaranteed to meet all requirements of the Fast Healthcare Interoperability Resources (FHIR) spec. If required, clients should perform their own validations.
This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE import androidx.health.connect.client.records.FhirVersion import androidx.health.connect.client.records.MedicalDataSource import androidx.health.connect.client.records.MedicalResource import androidx.health.connect.client.records.MedicalResourceId import androidx.health.connect.client.request.CreateMedicalDataSourceRequest import androidx.health.connect.client.request.UpsertMedicalResourceRequest // Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis if ( healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) != FEATURE_STATUS_AVAILABLE ) { return } // Get or create a `MedicalDataSource` val medicalDataSource: MedicalDataSource = healthConnectClient.createMedicalDataSource( CreateMedicalDataSourceRequest( fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"), displayName = "Test Data Source", fhirVersion = FhirVersion(4, 0, 1), ) ) // Insert `MedicalResource`s into the `MedicalDataSource` val medicalResources: List<MedicalResource> = healthConnectClient.upsertMedicalResources( listOf( UpsertMedicalResourceRequest( medicalDataSource.id, medicalDataSource.fhirVersion, medicationJsonToInsert, // a valid FHIR json string ) ) ) // Retrieve `fhirResourceType` type `MedicalResource`s with the specified `id`s from the // provided `MedicalDataSource` val retrievedMedicalResources: List<MedicalResource> = healthConnectClient.readMedicalResources( medicalResources.map { medicalResource: MedicalResource -> MedicalResourceId( dataSourceId = medicalDataSource.id, fhirResourceType = medicalResource.id.fhirResourceType, fhirResourceId = medicalResource.id.fhirResourceId, ) } )
| Throws | |
|---|---|
kotlin.IllegalArgumentException |
if the size of |
readMedicalResources
@ExperimentalPersonalHealthRecordApi
default @NonNull ReadMedicalResourcesResponse readMedicalResources(@NonNull ReadMedicalResourcesRequest request)
Reads MedicalResources by request, either ReadMedicalResourcesInitialRequest or ReadMedicalResourcesPageRequest.
A typical flow to read all MedicalResources that satisfy a certain criteria would be:
-
Create a
ReadMedicalResourcesInitialRequestwith desired criteria, and make a request. If successful, aReadMedicalResourcesResponseshould be returned. -
Use returned
ReadMedicalResourcesResponse.nextPageTokento create aReadMedicalResourcesPageRequestand make another request. Again, if successful, aReadMedicalResourcesResponseshould be returned. -
Repeat step 2 until
ReadMedicalResourcesResponse.nextPageTokenis null.
Regarding permissions, only permitted MedicalResources are returned. Specifically:
-
A caller without any read medical permissions such as
PERMISSION_READ_MEDICAL_DATA_VACCINES, or the write medical permissionPERMISSION_WRITE_MEDICAL_DATAis not permitted to read anyMedicalResource, including ones that it created. -
A caller with the write permission is permitted to read its own
MedicalResources of any type regardless whether it's in foreground or background. -
A caller with only a read permission, when in background, is only permitted to read its own
MedicalResources of the corresponding type. For example, if a caller only holdsPERMISSION_READ_MEDICAL_DATA_VACCINES, then when in background it is only permitted to read its ownMedicalResources withMedicalResource.MEDICAL_RESOURCE_TYPE_VACCINES. However, when it is in foreground or if it holdsPERMISSION_READ_HEALTH_DATA_IN_BACKGROUND, it is permitted to read all vaccinesMedicalResources, including ones that were written by other apps.
Each returned MedicalResource is not guaranteed to meet all requirements of the Fast Healthcare Interoperability Resources (FHIR) spec. If required, clients should perform their own validations.
This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE import androidx.health.connect.client.records.FhirVersion import androidx.health.connect.client.records.MedicalDataSource import androidx.health.connect.client.records.MedicalResource import androidx.health.connect.client.records.MedicalResource.Companion.MEDICAL_RESOURCE_TYPE_LABORATORY_RESULTS import androidx.health.connect.client.request.CreateMedicalDataSourceRequest import androidx.health.connect.client.request.ReadMedicalResourcesInitialRequest import androidx.health.connect.client.request.ReadMedicalResourcesPageRequest import androidx.health.connect.client.request.ReadMedicalResourcesRequest import androidx.health.connect.client.response.ReadMedicalResourcesResponse // Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis if ( healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) != FEATURE_STATUS_AVAILABLE ) { return } // Get or create a `MedicalDataSource` val medicalDataSource: MedicalDataSource = healthConnectClient.createMedicalDataSource( CreateMedicalDataSourceRequest( fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"), displayName = "Test Data Source", fhirVersion = FhirVersion(4, 0, 1), ) ) // Insert `MedicalResource`s into the `MedicalDataSource` healthConnectClient.upsertMedicalResources(exampleLabResults) // Read `MedicalResource`s back from the `MedicalDataSource` // Read 100 resources / page. See `pageSize` doc for defaults and limits. val pageSize = 100 // Prepare the initial read request. // All `MedicalResource`s in the given `MedicalDataSource`s and of given `medicalResourceType` // will be retrieved. val initialRequest: ReadMedicalResourcesRequest = ReadMedicalResourcesInitialRequest( MEDICAL_RESOURCE_TYPE_LABORATORY_RESULTS, setOf(medicalDataSource.id), pageSize = pageSize, ) // Continue reading pages until all `MedicalResource`s are read var pageToken: String? = null do { // Prepare paged request if needed val request: ReadMedicalResourcesRequest = if (pageToken == null) initialRequest else ReadMedicalResourcesPageRequest(pageToken, pageSize = pageSize) // Read `MedicalResource`s val response: ReadMedicalResourcesResponse = healthConnectClient.readMedicalResources(request) // Process `MedicalResource`s as desired val resources: List<MedicalResource> = response.medicalResources // Advance to next page pageToken = response.nextPageToken } while (pageToken != null)
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 |
@NonNull String recordId |
|
| Returns | |
|---|---|
@NonNull ReadRecordResponse<@NonNull T> |
The |
| 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.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 extends Record> |
the type of |
@NonNull ReadRecordsRequest<@NonNull T> request |
|
| Returns | |
|---|---|
@NonNull ReadRecordsResponse<@NonNull T> |
a response containing a collection of |
| 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.
| 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. |
upsertMedicalResources
@RequiresPermission(value = "android.permission.health.WRITE_MEDICAL_DATA")
@ExperimentalPersonalHealthRecordApi
default @NonNull List<@NonNull MedicalResource> upsertMedicalResources(
@NonNull List<@NonNull UpsertMedicalResourceRequest> requests
)
Inserts or updates a list of MedicalResources using UpsertMedicalResourceRequests.
In each request, from UpsertMedicalResourceRequest.dataSourceId, fhir resource type and fhir resource ID extracted from UpsertMedicalResourceRequest.data, a MedicalResourceId will be constructed. If there already exists a MedicalResource with that ID in Health Connect, then it will be updated, otherwise a new MedicalResource will be inserted.
For each UpsertMedicalResourceRequest, one MedicalResource will be returned, regardless whether it's updated or inserted. The order of the MedicalResources in the returned list will be the same as their corresponding UpsertMedicalResourceRequests in the input list.
Note that a MedicalDataSource needs to be created using createMedicalDataSource before any MedicalResources can be upserted for this source.
Regarding permissions:
-
Caller must hold
PERMISSION_WRITE_MEDICAL_DATAin order to call this API, otherwise aSecurityExceptionwill be thrown. -
With
PERMISSION_WRITE_MEDICAL_DATAgranted, caller is permitted to call this API in either foreground or background.
Medical data is represented using the "https://hl7.org/fhir/" standard. The FHIR resource provided in UpsertMedicalResourceRequest.data is expected to be valid for the specified FHIR version according to the FHIR spec. Structural validation checks such as resource structure, field types and presence of required fields will be performed, however these checks may not cover all FHIR spec requirements and are dependant on the backing implementation of Health Connect.
Data written to Health Connect should be for a single individual only. However, the API allows for multiple Patient resources to be written to account for the possibility of multiple Patient resources being present in one individual's medical record.
Each UpsertMedicalResourceRequest also has to meet the following requirements:
-
UpsertMedicalResourceRequest.datamust contain an "id" field and a "resourceType" field. The "resource type" must be one of the items in the accepted list of resource types inFhirResource. -
The FHIR resource does not have a "contained" field (holds contained resources).
-
FHIR versionof each request must matchMedicalDataSource.fhirVersionofUpsertMedicalResourceRequest.dataSourceId's correspondingMedicalDataSource.
If any request is failed to be processed for any reason, none of the requests will be inserted or updated in one transaction.
This feature is dependent on the version of HealthConnect installed on the device. To check if it's available call HealthConnectFeatures.getFeatureStatus and pass FEATURE_PERSONAL_HEALTH_RECORD as an argument. An UnsupportedOperationException would be thrown if the feature is not available.
import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_PERSONAL_HEALTH_RECORD import androidx.health.connect.client.HealthConnectFeatures.Companion.FEATURE_STATUS_AVAILABLE import androidx.health.connect.client.records.FhirVersion import androidx.health.connect.client.records.MedicalDataSource import androidx.health.connect.client.records.MedicalResource import androidx.health.connect.client.request.CreateMedicalDataSourceRequest import androidx.health.connect.client.request.UpsertMedicalResourceRequest // Ensure `FEATURE_PERSONAL_HEALTH_RECORD` is available before calling PHR apis if ( healthConnectClient.features.getFeatureStatus(FEATURE_PERSONAL_HEALTH_RECORD) != FEATURE_STATUS_AVAILABLE ) { return } // Get or create a `MedicalDataSource` val medicalDataSource: MedicalDataSource = healthConnectClient.createMedicalDataSource( CreateMedicalDataSourceRequest( fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"), displayName = "Test Data Source", fhirVersion = FhirVersion(4, 0, 1), ) ) // Insert `MedicalResource`s into the `MedicalDataSource` val medicalResources: List<MedicalResource> = healthConnectClient.upsertMedicalResources( listOf( UpsertMedicalResourceRequest( medicalDataSource.id, medicalDataSource.fhirVersion, medicationJsonToInsert, // a valid FHIR json string ) ) ) // Update `MedicalResource`s in the `MedicalDataSource` val updatedMedicalResources: List<MedicalResource> = healthConnectClient.upsertMedicalResources( listOf( UpsertMedicalResourceRequest( medicalDataSource.id, medicalDataSource.fhirVersion, // a valid FHIR json string // if this resource has the same type and ID as in `medicationJsonToInsert`, // this `upsertMedicalResources()` call will update the previously inserted // `MedicalResource` updatedMedicationJsonToInsert, ) ) )
| Parameters | |
|---|---|
@NonNull List<@NonNull UpsertMedicalResourceRequest> requests |
List of upsert requests. |
| Throws | |
|---|---|
kotlin.IllegalArgumentException |
if any request is failed to be processed for any reason such as invalid |
java.lang.SecurityException |
if caller does not hold |
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 import androidx.health.connect.client.records.StepsRecord import androidx.health.connect.client.time.TimeRangeFilter healthConnectClient.deleteRecords<StepsRecord>( timeRangeFilter = TimeRangeFilter.between(startTime, endTime) )
| Parameters | |
|---|---|
<T extends Record> |
Which type of |
@NonNull TimeRangeFilter timeRangeFilter |
The |
| 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 import androidx.health.connect.client.records.StepsRecord healthConnectClient.deleteRecords<StepsRecord>( recordIdsList = listOf(uid1, uid2), clientRecordIdsList = emptyList(), )
| Parameters | |
|---|---|
<T extends Record> |
Which type of |
@NonNull List<@NonNull String> recordIdsList |
List of |
@NonNull List<@NonNull String> clientRecordIdsList |
List of client record IDs of |
| 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 |
@NonNull String recordId |
|
| Returns | |
|---|---|
@NonNull ReadRecordResponse<@NonNull T> |
The |
| 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 |