同步数据

本指南与 Health Connect 1.1.0-alpha12 版本兼容。

大多数集成 Health Connect 的应用都有自己的数据存储,作为事实来源。Health Connect 提供多种方式来保持您的应用同步。

确保您的应用执行以下操作:

  • 将应用数据存储中新增或更新的数据馈送到 Health Connect。
  • 从 Health Connect 拉取数据更改,并反映在您的应用数据存储中。
  • 当应用数据存储中的数据被删除时,也从 Health Connect 中删除数据。

在每种情况下,请确保同步过程使 Health Connect 和您的应用数据存储保持一致。

将数据馈送到 Health Connect

同步过程的第一部分是将数据从您的应用数据存储馈送到 Health Connect 数据存储。

准备您的数据

通常,您的应用数据存储中的记录包含以下详细信息:

  • 唯一键,例如 UUID
  • 版本或时间戳。

设计您的应用数据存储,以跟踪哪些数据已馈送到 Health Connect。为此,请应用以下逻辑:

  • 提供更改列表和可用于检索自上次颁发令牌以来已更新的记录的令牌。
  • 跟踪导出数据上次修改的时间。

这些步骤对于确保只有新增或更新的数据被馈送到 Health Connect 至关重要。

将数据写入 Health Connect

要将数据馈送到 Health Connect,请执行以下步骤:

  1. 从您的应用数据存储中获取新增或更新的条目列表。
  2. 对于每个条目,创建一个适合该数据类型的 Record 对象。例如,为与体重相关的数据创建一个 WeightRecord 对象。
  3. 使用应用数据存储中的唯一键和版本详细信息,为每个 Record 指定一个 Metadata 对象。如果您的数据未进行版本控制,您可以使用当前时间戳的 Long 值作为替代。

    val recordVersion = 0L // Specify as needed
    val clientRecordId = "<You record's client ID"
    
    val record = WeightRecord(
        metadata = Metadata.activelyRecorded(
            clientRecordId = clientRecordId,
            clientRecordVersion = recordVersion,
            device = Device(type = Device.TYPE_SCALE)
        ),
        weight = Mass.kilograms(62.0),
        time = Instant.now(),
        zoneOffset = ZoneOffset.UTC,
    )
    healthConnectClient.insertRecords(listOf()(record))
    
    
  4. 使用 insertRecords 将数据插入或更新到 Health Connect。插入或更新数据意味着只要 clientRecordId 值存在于 Health Connect 数据存储中,并且 clientRecordVersion 高于现有值,Health Connect 中的任何现有数据都将被覆盖。否则,插入或更新的数据将作为新数据写入。

    healthConnectClient.insertRecords(arrayListOf(record))
    

要了解馈送数据的实际考量,请查阅“写入数据”的最佳实践。

存储 Health Connect ID

将记录插入或更新到 Health Connect 后,您的应用数据存储需要为每条记录存储 Health Connect id。这允许您的应用在拉取数据后检查每个传入更改是需要创建新记录还是更新现有记录。

insertRecords 函数返回一个 InsertRecordsResponse,其中包含 id 值列表。使用此响应获取记录 ID 并存储它们。

val response = healthConnectClient.insertRecords(arrayListOf(record))

for (recordId in response.recordIdsList) {
    // Store recordId to your app's datastore
}

从 Health Connect 拉取数据

同步过程的第二部分是从 Health Connect 将任何数据更改拉取到您的应用数据存储中。数据更改可以包括更新和删除。

获取更改令牌

要获取要从 Health Connect 拉取的更改列表,您的应用需要跟踪“更改令牌”。在请求“更改”时,您可以使用它们来返回数据更改列表和下次使用的新“更改令牌”。

要获取“更改令牌”,请调用 getChangesToken 并提供所需的数据类型。

val changesToken = healthConnectClient.getChangesToken(
    ChangesTokenRequest(recordTypes = setOf(WeightRecord::class))
)

检查数据更改

获取“更改令牌”后,使用它获取所有“更改”。我们建议创建一个循环来遍历所有“更改”,并检查是否有可用的数据更改。以下是具体步骤:

  1. 使用令牌调用 getChanges 以获取“更改”列表。
  2. 检查每个更改的类型是 UpsertionChange 还是 DeletionChange,并执行必要的操作。
    • 对于 UpsertionChange,只接受并非来自调用应用的更改,以确保您不会重复导入数据。
  3. 将下一个“更改令牌”分配为您的新令牌。
  4. 重复步骤 1-3,直到没有“更改”为止。
  5. 存储下一个令牌,并将其保留以供将来导入。
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
}

要了解拉取数据的实际考量,请查阅“同步数据”的最佳实践。

处理数据更改

将更改反映到您的应用数据存储中。对于 UpsertionChange,使用其 metadata 中的 idlastModifiedTime插入或更新记录。对于 DeletionChange,使用提供的 id删除记录。

从 Health Connect 删除数据

当用户从您的应用中删除自己的数据时,请确保数据也从 Health Connect 中移除。使用 deleteRecords 来完成此操作。此函数接受记录类型以及 idclientRecordId 值的列表,方便批量删除多条数据。另一种接受 timeRangeFilterdeleteRecords 也可用。

数据同步最佳实践

以下因素会影响同步过程。

令牌过期

由于未使用的“更改令牌”会在 30 天内过期,因此您必须使用一种同步策略,以避免在此类情况下丢失信息。您的策略可以包括以下方法:

  • 在您的应用数据存储中搜索最近消费的且也包含 Health Connect id 的记录。
  • 从 Health Connect 请求以特定时间戳开始的记录,然后将它们插入或更新到您的应用数据存储中。
  • 请求一个更改令牌,并将其保留以供下次需要时使用。

推荐的更改管理策略

如果您的应用收到无效或过期的“更改令牌”,我们建议根据其在您的逻辑中的应用,采用以下管理策略:

  • 读取并去重所有数据。这是最理想的策略。
    • 存储上次从 Health Connect 读取数据的时间戳。
    • 令牌过期时,从最新时间戳或过去 30 天重新读取所有数据。然后,使用标识符与之前读取的数据进行去重。
    • 理想情况下,应实现客户端 ID,因为它们是数据更新所必需的。
  • 仅读取自上次读取时间戳以来的数据。这会导致更改令牌过期时出现一些数据差异,但时间段较短,可能需要数小时到几天。
    • 存储上次从 Health Connect 读取数据的时间戳。
    • 令牌过期时,从此时间戳开始读取所有数据。
  • 先删除,然后读取过去 30 天的数据。这与首次集成时发生的情况更接近。
    • 删除应用从 Health Connect 读取的过去 30 天的所有数据。
    • 删除后,再次读取所有这些数据。
  • 在不进行去重的情况下读取过去 30 天的数据。这是最不理想的策略,会导致向用户显示重复数据。
    • 删除应用从 Health Connect 读取的过去 30 天的所有数据。
    • 允许重复条目。

数据类型更改令牌

如果您的应用独立使用多种数据类型,请为每种数据类型使用单独的更改令牌。只有当这些数据类型是同时使用或根本不使用时,才在 Changes Sync API 中使用多个数据类型的列表。

前台读取

应用只能在处于前台时从 Health Connect 读取数据。从 Health Connect 同步数据时,对 Health Connect 的访问可能会随时中断。例如,当从 Health Connect 读取大量数据时,您的应用必须处理同步中途的中断,并在下次应用打开时继续。

后台读取

您可以请求您的应用在后台运行并从 Health Connect 读取数据。如果您请求 Background Read 权限,您的用户可以授予您的应用在后台读取数据的权限。

导入时机

由于您的应用无法收到新数据的通知,请在以下两个时间点检查新数据:

  • 每次您的应用在前台变为活动状态时。在这种情况下,请使用生命周期事件。
  • 在您的应用保持在前台时,定期检查。当有新数据可用时通知用户,允许他们更新屏幕以反映更改。