В следующем примере показано, как считывать необработанные данные в рамках стандартного рабочего процесса.
Прочитать данные
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 (record in response.records) {
// Process each record
}
} catch (e: Exception) {
// Run error handling here
}
}
Вы также можете считывать данные в агрегированном виде, используя aggregate .
suspend fun readStepsByTimeRange(
healthConnectClient: HealthConnectClient,
startTime: Instant,
endTime: Instant
) {
try {
val response = healthConnectClient.aggregate(
AggregateRequest(
metrics = setOf(StepsRecord.COUNT_TOTAL),
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
// The result may be null if no data is available in the time range
val stepCount = response[StepsRecord.COUNT_TOTAL]
} catch (e: Exception) {
// Run error handling here
}
}
Прочитайте шаги для мобильных устройств.
При использовании Android 14 (уровень API 34) и SDK Extension версии 20 или выше, Health Connect обеспечивает подсчет шагов непосредственно на устройстве. Если какому-либо приложению предоставлено разрешение READ_STEPS , Health Connect начинает фиксировать шаги на устройстве под управлением Android, и пользователи автоматически видят данные о шагах, добавляемые в записи Health Connect Steps .
Чтобы проверить наличие функции подсчета шагов на устройстве, необходимо убедиться, что устройство работает под управлением Android 14 (уровень API 34) и имеет как минимум версию расширения SDK 20. Для этого можно использовать следующий код:
val isStepTrackingAvailable =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 20
При использовании приложения Health Connect для отслеживания шагов на мобильных устройствах в качестве DataOrigin используется имя пакета android . Если ваше приложение просто считывает агрегированные данные о количестве шагов с помощью aggregate и не фильтрует по DataOrigin , шаги, сделанные на устройстве, автоматически включаются в общую сумму.
Если вашему приложению необходимо считывать данные о шагах, выполняемых на устройстве, или если оно отображает данные о шагах с разбивкой по исходному приложению или устройству, вы можете запросить записи, где DataOrigin равен android . Если ваше приложение отображает атрибуцию для данных о шагах, вам следует атрибутивировать данные из пакета android текущему устройству. Вы можете сделать это, используя метку, например, «Ваш телефон», получив имя устройства с помощью Settings.Global.getString(resolver, Settings.Global.DEVICE_NAME) или проверив поле Device в метаданных записи.
В следующем примере показано, как считывать агрегированные данные о количестве шагов, сделанных на мобильном устройстве, с фильтрацией по источнику данных android :
suspend fun readStepsByTimeRange(
healthConnectClient: HealthConnectClient,
startTime: Instant,
endTime: Instant
) {
try {
val response = healthConnectClient.aggregate(
AggregateRequest(
metrics = setOf(StepsRecord.COUNT_TOTAL),
timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
dataOriginFilter = setOf(DataOrigin("android"))
)
)
// The result may be null if no data is available in the time range
val stepCount = response[StepsRecord.COUNT_TOTAL]
} catch (e: Exception) {
// Run error handling here
}
}
Подсчет шагов на устройстве
Подробнее об функции подсчета шагов на устройстве:
- Использование датчика : Health Connect использует датчик
TYPE_STEP_COUNTERизSensorManager. Этот датчик оптимизирован для низкого энергопотребления, что делает его идеальным для непрерывного фонового отслеживания шагов. - Детализация данных : Для экономии заряда батареи данные о количестве шагов обычно объединяются в пакеты и записываются в базу данных Health Connect не чаще одного раза в минуту.
- Атрибуция : Как упоминалось ранее, все шаги, записанные этой функцией на устройстве, приписываются имени пакета
androidвDataOrigin. - Активация : Механизм подсчета шагов на устройстве активируется только в том случае, если хотя бы одному приложению на устройстве предоставлено разрешение
READ_STEPSв рамках Health Connect.
Пример фонового чтения
Для чтения данных в фоновом режиме укажите следующие права доступа в файле манифеста:
<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 дней.
Ограничения можно снять, запросив разрешение на чтение .
Для чтения исторических данных необходимо указать имя пакета в виде объекта DataOrigin в параметре dataOriginFilter вашего ReadRecordsRequest .
В следующем примере показано, как указать имя пакета при чтении записей частоты сердечных сокращений:
try {
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = HeartRateRecord::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 дней
По умолчанию все приложения могут считывать данные из Health Connect за период до 30 дней до момента предоставления соответствующего разрешения.
Если вам необходимо расширить права на чтение сверх каких-либо ограничений по умолчанию , запросите разрешение PERMISSION_READ_HEALTH_DATA_HISTORY . В противном случае, без этого разрешения, попытка чтения записей старше 30 дней приведет к ошибке.
История разрешений для удалённого приложения
Если пользователь удалит ваше приложение, все разрешения, включая разрешение на просмотр истории, будут отозваны. Если пользователь переустановит ваше приложение и снова предоставит разрешение, будут действовать те же ограничения по умолчанию , и ваше приложение сможет считывать данные из Health Connect за период до 30 дней до этой новой даты.
Например, предположим, пользователь удаляет ваше приложение 10 мая 2023 года, а затем переустанавливает его 15 мая 2023 года, предоставляя права на чтение. Самая ранняя дата, с которой ваше приложение теперь может читать данные по умолчанию, — 15 апреля 2023 года .
Обработка исключений
В случае возникновения проблем Health Connect генерирует стандартные исключения для операций CRUD. Ваше приложение должно перехватывать и обрабатывать каждое из этих исключений соответствующим образом.
В каждом методе класса HealthConnectClient перечислены исключения, которые могут быть сгенерированы. В целом, ваше приложение должно обрабатывать следующие исключения:
| Исключение | Описание | Рекомендуемые лучшие практики |
|---|---|---|
IllegalStateException | Произошло одно из следующих событий:
| Перед отправкой запроса сначала обработайте возможные проблемы с входными данными. Желательно присваивать значения переменным или использовать их в качестве параметров в пользовательской функции, а не использовать их напрямую в запросах, чтобы иметь возможность применять стратегии обработки ошибок. |
IOException | При чтении и записи данных с диска возникают проблемы. | Чтобы избежать этой проблемы, предлагаем следующие варианты:
|
RemoteException | Ошибки возникли внутри или при взаимодействии с базовой службой, к которой подключается SDK. Например, ваше приложение пытается удалить запись с заданным uid . Однако исключение возникает после того, как приложение, проверив данные в базовом сервисе, обнаруживает, что запись не существует. | Чтобы избежать этой проблемы, предлагаем следующие варианты:
|
SecurityException | Проблемы возникают, когда запросы требуют разрешений, которые не предоставлены. | Чтобы этого избежать, убедитесь, что вы указали использование типов данных Health Connect для опубликованного приложения. Кроме того, необходимо указать разрешения Health Connect в файле манифеста и в вашем Activity . |