Most apps that integrate with Health Connect have their own datastore that serves as the source of truth. Health Connect provides ways to keep your app in sync.
Make sure your app does the following:
- Feeds new or updated data from your app's datastore to Health Connect.
- Pulls data changes from Health Connect, which are reflected in your app's datastore.
- Deletes data from Health Connect when it's deleted in your app's datastore.
In each case, make sure that the syncing process keeps both Health Connect and your app's datastore aligned.
Feed data to Health Connect
The first part of the syncing process is to feed data from your app's datastore to the Health Connect datastore.
Prepare your data
Usually, records in your app's datastore have the following details:
- A unique key, such as a
UUID
. - A version or timestamp.
Design your app's datastore to keep track of what data has already been fed to Health Connect. To achieve this, apply the following logic:
- Provide a list of changes and a token that can be used to retrieve records that have updates since the last token was issued.
- Track the last time the exported data was modified.
These steps are essential to ensure that only new or updated data is fed to Health Connect.
Write data to Health Connect
To feed data into Health Connect, carry out the following steps:
- Obtain a list of new or updated entries from your app's datastore.
- For each entry, create a
Record
object appropriate for that data type. For example, create aWeightRecord
object for data related to weight. Specify a
Metadata
object with eachRecord
using the unique key and version details from your app's datastore. If your data is not versioned, you can use theLong
value of the current timestamp as an alternative.val record = WeightRecord( metadata = Metadata( clientRecordId = "<Your record's Client ID>", clientRecordVersion = <Your record's version> ), weight = weight, time = time, zoneOffset = zoneOffset )
Upsert data to Health Connect using
insertRecords
. Upserting data means that any existing data in Health Connect gets overwritten as long as theclientRecordId
values exist in the Health Connect datastore, and theclientRecordVersion
is higher than the existing value. Otherwise, the upserted data is written as new data.healthConnectClient.insertRecords(arrayListOf(record))
To learn about the practical considerations for feeding data, check out the best practices for Write data.
Store Health Connect IDs
After upserting your records to Health Connect, your app's datastore needs to
store the Health Connect id
for each record. This allows your app to check
if each incoming change requires creating a new record, or
updating an existing record, after you pull the data.
The insertRecords
function returns a
InsertRecordsResponse
that contains the list of id
values.
Use the response to get the Record IDs and store them.
val response = healthConnectClient.insertRecords(arrayListOf(record))
for (recordId in response.recordIdsList) {
// Store recordId to your app's datastore
}
Pull data from Health Connect
The second part of the syncing process is to pull for any data changes from Health Connect to your app's datastore. The data changes can include updates and deletions.
Get a Changes token
To get a list of changes to pull from Health Connect, your app needs to keep track of Changes tokens. You can use them when requesting Changes to return both a list of data changes, and a new Changes token to be used next time.
To obtain a Changes token, call getChangesToken
and
supply the required data types.
val changesToken = healthConnectClient.getChangesToken(
ChangesTokenRequest(recordTypes = setOf(WeightRecord::class))
)
Check for data changes
Now that you've obtained a Changes token, use it to get all Changes. We recommend creating a loop to get through all the Changes where it checks if there are available data changes. Here are the following steps:
- Call
getChanges
using the token to obtain a list of Changes. - Check each change whether its type of change is an
UpsertionChange
or aDeletionChange
, and perform the necessary operations.- For
UpsertionChange
, only take changes that didn't come from the calling app to make sure you're not re-importing data.
- For
- Assign the next Changes token as your new token.
- Repeat Steps 1-3 until there are no Changes left.
- Store the next token and reserve it for a future import.
suspend fun processChanges(token: String): String {
var nextChangesToken = token
do {
val response = healthConnectClient.getChanges(nextChangesToken)
response.changes.forEach { change ->
when (change) {
is UpsertionChange ->
if (change.record.metadata.dataOrigin.packageName != context.packageName) {
processUpsertionChange(change)
}
is DeletionChange -> processDeletionChange(change)
}
}
nextChangesToken = response.nextChangesToken
} while (response.hasMore)
// Return and store the changes token for use next time.
return nextChangesToken
}
To learn about the practical considerations for pulling data, check out the best practices for Sync data.
Process data changes
Reflect the changes to your app's datastore. For UpsertionChange
, use the id
and the lastModifiedTime
from its metadata
to upsert the record.
For DeletionChange
, use the id
provided to delete the record.
Delete data from Health Connect
When a user deletes their own data from your app, make sure that the data is
also removed from Health Connect. Use deleteRecords
to do this. This takes a record type and list of id
and clientRecordId
values, which makes it convenient to batch multiple data for deletion. An
alternative deleteRecords
that takes in a timeRangeFilter
is also available.