本指南介绍了在 Health Connect 中写入或更新数据的过程。
设置数据结构
在写入数据之前,我们需要先设置记录。对于 50 多种数据类型,每种数据类型都有其各自的结构。有关可用数据类型的更多详细信息,请参阅 Jetpack 参考。
基本记录
Health Connect 中的 步数 数据类型捕获用户在读数之间采取的步数。步数代表健康、健身和健康平台之间的一种常见测量值。
以下示例显示了如何设置步数数据
val stepsRecord = StepsRecord(
count = 120,
startTime = START_TIME,
endTime = END_TIME,
startZoneOffset = START_ZONE_OFFSET,
endZoneOffset = END_ZONE_OFFSET
)
具有计量单位的记录
Health Connect 可以存储值及其计量单位,以提供准确性。一个示例是 营养 数据类型,它非常广泛且全面。它包括各种可选的营养素字段,从总碳水化合物到维生素。每个数据点都代表作为膳食或食物的一部分可能消耗的营养素。
在此数据类型中,所有营养素都以 Mass
为单位表示,而 energy
以 Energy
为单位表示。
以下示例显示了如何为吃过香蕉的用户设置营养数据
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
)
具有系列数据的记录
Health Connect 可以存储一系列数据。一个示例是 心率 数据类型,它捕获在读数之间检测到的心跳样本序列。
在此数据类型中,参数 samples
由 心率样本 列表表示。每个样本都包含一个 beatsPerMinute
值和一个 time
值。
以下示例显示了如何设置心率系列数据
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(),
)
}
)
写入数据
Health Connect 中的常见工作流程之一是写入数据。要添加记录,请使用 insertRecords
。
以下示例显示了如何通过插入步数来写入数据
suspend fun insertSteps(healthConnectClient: HealthConnectClient) {
try {
val stepsRecord = StepsRecord(
count = 120,
startTime = START_TIME,
endTime = END_TIME,
startZoneOffset = START_ZONE_OFFSET,
endZoneOffset = END_ZONE_OFFSET
)
healthConnectClient.insertRecords(listOf(stepsRecord))
} catch (e: Exception) {
// Run error handling here
}
}
更新数据
如果您需要更改一个或多个记录,尤其是在您需要 同步 应用数据存储与 Health Connect 中的数据时,您可以更新您的数据。有两种方法可以更新现有数据,这取决于用于查找记录的标识符。
元数据
首先值得检查一下Metadata
类,因为更新数据时需要用到它。在创建时,Health Connect 中的每个Record
都有一个metadata
字段。以下属性与同步相关。
属性 | 描述 |
---|---|
id
|
Health Connect 中的每个Record 都有一个唯一的id 值。Health Connect 在插入新记录时会自动填充此值。 |
lastModifiedTime
|
每个Record 还会跟踪上次修改记录的时间。Health Connect 会自动填充此值。 |
clientRecordId
|
每个Record 可以有一个唯一的 ID 与之关联,用作您应用数据存储中的参考。您的应用提供此值。 |
clientRecordVersion
|
如果记录具有clientRecordId ,则可以使用clientRecordVersion 来确保数据与您应用数据存储中的版本保持同步。您的应用提供此值。 |
通过 Record ID 更新
要更新数据,请先准备所需的记录。如有必要,对记录进行任何更改。然后,调用updateRecords
来进行更改。
以下示例展示了如何更新数据。为此,每个记录的时区偏移值都调整为 PST。
suspend fun updateSteps(
healthConnectClient: HealthConnectClient,
prevRecordStartTime: Instant,
prevRecordEndTime: Instant
) {
try {
val request = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = StepsRecord::class,
timeRangeFilter = TimeRangeFilter.between(
prevRecordStartTime,
prevRecordEndTime
)
)
)
val newStepsRecords = arrayListOf<StepsRecord>()
for (record in request.records) {
// Adjusted both offset values to reflect changes
val sr = StepsRecord(
count = record.count,
startTime = record.startTime,
startZoneOffset = record.startTime.atZone(ZoneId.of("PST")).offset,
endTime = record.endTime,
endZoneOffset = record.endTime.atZone(ZoneId.of("PST")).offset,
metadata = record.metadata
)
newStepsRecords.add(sr)
}
client.updateRecords(newStepsRecords)
} catch (e: Exception) {
// Run error handling here
}
}
通过 Client Record ID 执行 Upsert
如果您使用可选的 Client Record ID 和 Client Record Version 值,建议使用insertRecords
而不是updateRecords
。
insertRecords
函数能够执行 Upsert 操作。如果数据根据给定的 Client Record ID 集存在于 Health Connect 中,则会覆盖它。否则,它将作为新数据写入。当您需要同步 应用数据存储中的数据到 Health Connect 时,此方案非常有用。
以下示例展示了如何对从应用数据存储中提取的数据执行 Upsert 操作。
suspend fun pullStepsFromDatastore() : ArrayList<StepsRecord> {
val appStepsRecords = arrayListOf<StepsRecord>()
// Pull data from app datastore
// ...
// Make changes to data if necessary
// ...
// Store data in appStepsRecords
// ...
var sr = StepsRecord(
// Assign parameters for this record
metadata = Metadata(
clientRecordId = cid
)
)
appStepsRecords.add(sr)
// ...
return appStepsRecords
}
suspend fun upsertSteps(
healthConnectClient: HealthConnectClient,
newStepsRecords: ArrayList<StepsRecord>
) {
try {
healthConnectClient.insertRecords(newStepsRecords)
} catch (e: Exception) {
// Run error handling here
}
}
之后,您可以在主线程中调用这些函数。
upsertSteps(healthConnectClient, pullStepsFromDatastore())
Client Record Version 中的值检查
如果您的 Upsert 数据流程包含 Client Record Version,Health Connect 会在clientRecordVersion
值中执行比较检查。如果插入数据的版本高于现有数据的版本,则会执行 Upsert 操作。否则,流程会忽略更改,并且值保持不变。
要在数据中包含版本控制,您需要使用基于版本控制逻辑的Long
值为Metadata.clientRecordVersion
提供值。
val sr = StepsRecord(
count = count,
startTime = startTime,
startZoneOffset = startZoneOffset,
endTime = endTime,
endZoneOffset = endZoneOffset,
metadata = Metadata(
clientRecordId = cid,
clientRecordVersion = version
)
)
Upsert 操作不会在每次更改时自动递增version
,从而防止意外覆盖数据的情况发生。因此,您必须手动为其提供更高的值。
数据写入最佳实践
应用只能将自身来源的数据写入 Health Connect。
如果应用中的数据是从其他应用导入的,则其他应用有责任将其自身数据写入 Health Connect。
最好实现处理写入异常的逻辑,例如数据超出范围或内部系统错误。您可以在作业调度机制上应用回退和重试策略。如果最终无法写入 Health Connect,请确保您的应用能够继续执行导出操作。不要忘记记录和报告错误以帮助诊断。
在跟踪数据时,您可以根据应用写入数据的方式遵循以下几条建议。
被动跟踪
这包括执行被动健身或健康跟踪的应用,例如在后台持续记录步数或心率。
您的应用需要定期将数据写入 Health Connect,方法如下:
- 每次同步时,仅写入自上次同步以来已修改的新数据和更新的数据。
- 将请求分成最多 1000 条记录/写入请求。
- 使用
WorkManager
来安排定期后台任务,时间间隔至少为 15 分钟。 限制任务仅在设备空闲且电池电量不低时运行。
val constraints = Constraints.Builder() .requiresBatteryNotLow() .requiresDeviceIdle(true) .build() val writeDataWork = PeriodicWorkRequestBuilder<WriteDataToHealthConnectWorker>( 15, TimeUnit.MINUTES, 5, TimeUnit.MINUTES ) .setConstraints(constraints) .build()
主动跟踪
这包括执行基于事件的跟踪的应用,例如锻炼和睡眠,或手动用户输入,例如营养。这些记录是在应用处于前台时创建的,或者在很少情况下,应用在一天中使用几次时创建。
确保您的应用不会在整个事件期间持续运行 Health Connect。
数据必须以以下两种方式之一写入 Health Connect:
- 在事件完成后将数据同步到 Health Connect。例如,在用户结束跟踪的锻炼会话时同步数据。
- 使用
WorkManager
安排一次性任务以稍后同步数据。
写入粒度和频率的最佳实践
将数据写入 Health Connect 时,请使用合适的解析度。使用合适的解析度有助于减少存储负载,同时仍能保持数据的一致性和准确性。数据解析度包含两方面内容:
- 写入频率:您的应用推送任何新数据到 Health Connect 的频率。例如,每 15 分钟写入一次新数据。
- 写入数据的粒度:推送的数据采样的频率。例如,每 5 秒写入一次心率样本。并非每种数据类型都需要相同的采样率。与每秒更新步数数据相比,每 60 秒更新一次步数数据的好处不大。但是,更高的采样率可以让用户更详细、更细致地了解其健康和健身数据。采样率频率应在细节和性能之间取得平衡。
写入全天监控的数据
对于持续收集的数据(如步数),您的应用应至少每天通过 Health Connect 写入一次数据,时间间隔为 15 分钟。
数据类型 |
单位 |
预期 |
示例 |
步数 |
步 |
每 1 分钟 |
23:14 - 23:15 - 5 步 23:16 - 23:17 - 22 步 23:17 - 23:18 - 8 步 |
步频 |
步/分钟 |
每 1 分钟 |
23:14 - 23:15 - 5 步/分钟 23:16 - 23:17 - 22 步/分钟 23:17 - 23:18 - 8 步/分钟 |
轮椅推数 |
次 |
每 1 分钟 |
23:14 - 23:15 - 5 次 23:16 - 23:17 - 22 次 23:17 - 23:18 - 8 次 |
主动消耗卡路里 |
卡路里 |
每 15 分钟 |
23:15 - 23:30 - 2 卡路里 23:30 - 23:45 - 25 卡路里 23:45 - 00:00 - 5 卡路里 |
总消耗卡路里 |
卡路里 |
每 15 分钟 |
23:15 - 23:30 - 16 卡路里 23:30 - 23:45 - 16 卡路里 23:45 - 00:00 - 16 卡路里 |
距离 |
公里/分钟 |
每 1 分钟 |
23:14-23:15 - 0.008 公里 23:16 - 23:16 - 0.021 公里 23:17 - 23:18 - 0.012 公里 |
海拔升高 |
米 |
每 1 分钟 |
20:36 - 20:37 - 3.048 米 20:39 - 20:40 - 3.048 米 23:23 - 23:24 - 9.144 米 |
攀爬楼层 |
层 |
每 1 分钟 |
23:14 - 23:15 - 5 层 23:16 - 23:16 - 22 层 23:17 - 23:18 - 8 层 |
心率 |
次/分钟 |
每 1 分钟 |
早上 6:11 - 55 次/分钟 |
心率变异性 RMSSD |
毫秒 |
每 1 分钟 |
早上 6:11 - 23 毫秒 |
呼吸频率 |
次/分钟 |
每 1 分钟 |
23:14 - 23:15 - 60 次/分钟 23:16 - 23:16 - 62 次/分钟 23:17 - 23:18 - 64 次/分钟 |
血氧饱和度 |
% |
每 1 小时 |
6:11 - 95.208% |
写入会话
数据应在锻炼或睡眠会话结束时写入 Health Connect。
最佳实践是,任何睡眠会话或锻炼会话都应使用录制设备和相应的元数据(包括RecordingMethod
)一起写入。
至少,您的应用应遵循下面“预期”列中的指南。如果可能,请遵循“最佳”指南。
在锻炼期间跟踪的数据
数据类型 |
单位 |
预期 |
最佳 |
示例 |
步数 |
步 |
每 1 分钟 |
每 1 秒 |
23:14-23:15 - 5 步 23:16 - 23:17 - 22 步 23:17 - 23:18 - 8 步 |
步频 |
步/分钟 |
每 1 分钟 |
每 1 秒 |
23:14-23:15 - 35 步/分钟 23:16 - 23:17 - 37 步/分钟 23:17 - 23:18 - 40 步/分钟 |
轮椅推数 |
次 |
每 1 分钟 |
每 1 秒 |
23:14-23:15 - 5 次 23:16 - 23:17 - 22 次 23:17 - 23:18 - 8 次 |
自行车踏频 |
转/分钟 |
每 1 分钟 |
每 1 秒 |
23:14-23:15 - 65 转/分钟 23:16 - 23:17 - 70 转/分钟 23:17 - 23:18 - 68 转/分钟 |
功率 |
瓦特 |
每 1 分钟 |
每 1 秒 |
23:14-23:15 - 250 瓦特 23:16 - 23:17 - 255 瓦特 23:17 - 23:18 - 245 瓦特 |
速度 |
公里/分钟 |
每 1 分钟 |
每 1 秒 |
23:14-23:15 - 0.3 公里/分钟 23:16 - 23:17 - 0.4 公里/分钟 23:17 - 23:18 -0.4 公里/分钟 |
距离 |
公里/米 |
每 1 分钟 |
每 1 秒 |
23:14-23:15 - 0.008 公里 23:16 - 23:16 - 0.021 公里 23:17 - 23:18 - 0.012 公里 |
主动消耗卡路里 |
卡路里 |
每 1 分钟 |
每 1 秒 |
23:14-23:15 - 20 卡路里 23:16 - 23:17 - 20 卡路里 23:17 - 23:18 - 25 卡路里 |
总消耗卡路里 |
卡路里 |
每 1 分钟 |
每 1 秒 |
23:14-23:15 - 36 卡路里 23:16 - 23:17 - 36 卡路里 23:17 - 23:18 - 41 卡路里 |
海拔升高 |
米 |
每 1 分钟 |
每 1 秒 |
20:36 - 20:37 - 3.048 米 20:39 - 20:40 - 3.048 米 23:23 - 23:24 - 9.144 米 |
锻炼路线 |
纬度/经度/高度 |
每 3-5 秒 |
每 1 秒 |
|
心率 |
次/分钟 |
每 1 分钟 |
每 1 秒 |
23:14-23:15 - 150 次/分钟 23:16 - 23:17 -152 次/分钟 23:17 - 23:18 - 155 次/分钟 |
在睡眠期间跟踪的数据
数据类型 |
单位 |
预期样本 |
示例 |
睡眠分期 |
阶段 |
每个睡眠阶段的细粒度时间段 |
23:46 - 23:50 - 清醒 23:50 - 23:56 - 浅睡 23:56 - 00:16 - 深睡 |
静息心率 |
次/分钟 |
单个每日值(预期在早上第一时间获取) |
早上 6:11 - 60 次/分钟 |
血氧饱和度 |
% |
单个每日值(预期在早上第一时间获取) |
6:11 - 95.208% |