以下示例展示了如何在常见工作流中读取原始数据。
读取数据
Health Connect 允许应用在前台和后台运行时读取数据存储区中的数据:
前台读取:当应用在前台运行时,您通常可以从 Health Connect 读取数据。在这些情况下,您可以考虑使用前台服务来运行此操作,以防用户或系统在读取操作期间将您的应用置于后台。
后台读取:通过向用户请求额外权限,您可以在用户或系统将您的应用置于后台后读取数据。查看完整的后台读取示例。
Health Connect 中的“步数”数据类型会记录用户在两次读取数据之间完成的步数。步数是各健身和健康平台的常见测量内容。借助 Health Connect,您可以轻松读取和写入步数数据。
如需读取记录,请创建一个 ReadRecordsRequest
并在调用 readRecords
时提供它。
以下示例展示了如何读取特定时间段内用户的步数数据。如需查看使用 SensorManager
的扩展示例,请参阅步数数据指南。
suspend fun readStepsByTimeRange(
healthConnectClient: HealthConnectClient,
startTime: Instant,
endTime: Instant
) {
try {
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
StepsRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
for (stepRecord in response.records) {
// Process each step record
}
} catch (e: Exception) {
// Run error handling here
}
}
后台读取示例
如需在后台读取数据,请在清单文件中声明以下权限:
<application>
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND" />
...
</application>
以下示例展示了如何使用 WorkManager
在后台读取特定时间段内用户的步数数据:
class ScheduleWorker(private val appContext: Context, workerParams: WorkerParameters):
CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result {
// Read data and process it.
...
// Return success indicating successful data retrieval
return Result.success()
}
}
if (healthConnectClient
.features
.getFeatureStatus(
HealthConnectFeatures.FEATURE_READ_HEALTH_DATA_IN_BACKGROUND
) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE) {
// Check if necessary permission is granted
val grantedPermissions = healthConnectClient.permissionController.getGrantedPermissions()
if (PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND !in grantedPermissions) {
// Perform read in foreground
...
} else {
// Schedule the periodic work request in background
val periodicWorkRequest = PeriodicWorkRequestBuilder<ScheduleWorker>(1, TimeUnit.HOURS)
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"read_health_connect",
ExistingPeriodicWorkPolicy.KEEP,
periodicWorkRequest
)
}
} else {
// Background reading is not available, perform read in foreground
...
}
ReadRecordsRequest
参数的默认 pageSize
值为 1000。如果单个 readResponse
中的记录数超出了请求的 pageSize
,您需要使用 pageToken
迭代响应的所有页面,以检索所有记录。不过,请务必避免出现速率限制问题。
PageToken 读取示例
建议使用 pageToken
读取记录,以检索请求时间段内的所有可用数据。
以下示例展示了如何读取所有记录,直到所有页面令牌耗尽为止:
val type = HeartRateRecord::class
val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofDays(7))
try {
var pageToken: String? = null
do {
val readResponse =
healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = type,
timeRangeFilter = TimeRangeFilter.between(
startTime,
endTime
),
pageToken = pageToken
)
)
val records = readResponse.records
// Do something with records
pageToken = readResponse.pageToken
} while (pageToken != null)
} catch (quotaError: IllegalStateException) {
// Backoff
}
如需了解读取大型数据集的最佳实践,请参阅规划以避免速率限制。
读取之前写入的数据
如果某个应用之前已向 Health Connect 写入了记录,那么该应用可以读取历史数据。这适用于以下场景:在用户重新安装应用后,应用需要与 Health Connect 重新同步。
存在一些阅读限制:
对于 Android 14 及更高版本
- 应用读取自己的数据不受历史限制。
- 对应用读取其他数据的 30 天限制。
对于 Android 13 及更低版本
- 应用读取任何数据的 30 天限制。
您可以通过请求读取权限来解除这些限制。
如需读取历史数据,您需要在 ReadRecordsRequest
的 dataOriginFilter
参数中,将软件包名称指示为 DataOrigin
对象。
以下示例展示了如何在读取步数记录时指示软件包名称:
try {
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = StepsRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
dataOriginFilter = setOf(DataOrigin("com.my.package.name"))
)
)
for (record in response.records) {
// Process each record
}
} catch (e: Exception) {
// Run error handling here
}
读取 30 天前的数据
默认情况下,所有应用都可以读取在首次授予任何权限前最多 30 天的 Health Connect 数据。
如果您需要超出任何默认限制来扩展读取权限,请请求 PERMISSION_READ_HEALTH_DATA_HISTORY
。否则,如果没有此权限,尝试读取 30 天之前的记录将导致错误。
已删除应用的权限记录
如果用户删除您的应用,系统会撤消所有权限,包括历史记录权限。如果用户重新安装您的应用并再次授予权限,则系统会应用相同的默认限制,并且您的应用可以读取从该新日期最多回推 30 天的 Health Connect 数据。
例如,假设用户在 2023 年 5 月 10 日删除了您的应用,然后在 2023 年 5 月 15 日重新安装该应用,并授予读取权限。现在,您的应用可读取的数据最早可追溯至 2023 年 4 月 15 日(默认)。