我正在使用 HealthConnect API 根据各个记录中的手动求和值来验证聚合卡路里数据。我在 Kotlin 中实现了一个函数,用于获取过去 30 天内每一天的每日记录和汇总金额。然而,我一直发现这两个总数之间存在差异。
这是我如何获取和聚合数据的示例:
suspend fun validateCaloriesData(healthConnectClient: HealthConnectClient) {
// Time zone and date setup
val zoneId = ZoneId.systemDefault()
val endTime = Instant.now().atZone(zoneId).truncatedTo(ChronoUnit.DAYS)
val startTime = endTime.minusDays(30)
var currentDay = startTime
while (currentDay.isBefore(endTime)) {
val startOfDay = currentDay.toInstant()
val endOfDay = currentDay.plusDays(1).toInstant()
val dailyRecords = mutableListOf<Double>()
try {
val records = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = TotalCaloriesBurnedRecord::class,
timeRangeFilter = TimeRangeFilter.between(startOfDay, endOfDay),
pageSize = 2000,
pageToken = null,
ascendingOrder = true
)
)
records.records.forEach {
dailyRecords.add(it.energy.inKilocalories ?: 0.0)
}
val sumOfDailyRecords = dailyRecords.sum()
val response = healthConnectClient.aggregate(
AggregateRequest(
metrics = setOf(TotalCaloriesBurnedRecord.ENERGY_TOTAL),
timeRangeFilter = TimeRangeFilter.between(startOfDay, endOfDay)
)
)
val aggregatedCalories = response[TotalCaloriesBurnedRecord.ENERGY_TOTAL]?.inKilocalories ?: 0.0
if (sumOfDailyRecords != aggregatedCalories) {
Log.e("DailyCaloriesValidation", "Discrepancy found on day $currentDay: Manual sum is $sumOfDailyRecords but aggregated is $aggregatedCalories")
}
} catch (e: Exception) {
Log.e("DailyCaloriesValidation", "Error reading or aggregating calories for day $currentDay: ${e.message}")
}
currentDay = currentDay.plusDays(1)
}
}
和日志:
E/DailyCaloriesValidation( 8147): Discrepancy found on day 2024-04-13T00:00+02:00[Europe/Paris]: Manual sum is 100.0 but aggregated is 1707.009
E/DailyCaloriesValidation( 8147): Discrepancy found on day 2024-04-10T00:00+02:00[Europe/Paris]: Manual sum is 188.0 but aggregated is 1780.543
尝试下面的代码
fun validateCaloriesData(healthConnectClient: HealthConnectClient) {
// Time zone and date setup
val zoneId = ZoneId.systemDefault()
val endTime = Instant.now().atZone(zoneId).truncatedTo(ChronoUnit.DAYS)
val startTime = endTime.minusDays(30)
var currentDay = startTime
while (currentDay.isBefore(endTime)) {
val startOfDay = currentDay.toInstant()
val endOfDay = currentDay.plusDays(1).toInstant()
try {
val dailyRecords = mutableListOf<Double>()
// Fetch records for the current day
val records = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = TotalCaloriesBurnedRecord::class,
timeRangeFilter = TimeRangeFilter.between(startOfDay, endOfDay),
pageSize = 2000,
pageToken = null,
ascendingOrder = true
)
)
// Iterate through the records and calculate the sum
records.records.forEach {
dailyRecords.add(it.energy.inKilocalories ?: 0.0)
}
val sumOfDailyRecords = dailyRecords.sum()
// Aggregate the records for the current day
val response = healthConnectClient.aggregate(
AggregateRequest(
metrics = setOf(TotalCaloriesBurnedRecord.ENERGY_TOTAL),
timeRangeFilter = TimeRangeFilter.between(startOfDay, endOfDay)
)
)
// Retrieve the aggregated sum for the current day
val aggregatedCalories = response[TotalCaloriesBurnedRecord.ENERGY_TOTAL]?.inKilocalories ?: 0.0
// Compare the manual sum with the aggregated sum
if (Math.abs(sumOfDailyRecords - aggregatedCalories) > 0.001) {
// Log a warning if there's a significant discrepancy
Log.w("DailyCaloriesValidation", "Discrepancy found on day $currentDay: Manual sum is $sumOfDailyRecords but aggregated is $aggregatedCalories")
}
} catch (e: Exception) {
// Log any errors that occur during data retrieval or aggregation
Log.e("DailyCaloriesValidation", "Error processing data for day $currentDay: ${e.message}")
}
// Move to the next day
currentDay = currentDay.plusDays(1)
}
}
删除了不必要的变量 currentDay 并将初始化移至循环控制,删除了 try 块内 dailyRecords 列表的创建以确保其始终初始化。使用 Math.abs 以小容差(0.001)比较和来处理浮点精度问题
如果您仍然遇到问题,您可以在我的答案下面发表评论,我很乐意为您提供帮助。