1. 소개
헬스 커넥트란 무엇인가요?
헬스 커넥트는 Android 앱 개발자를 위한 건강 데이터 플랫폼입니다. 사용자의 건강 및 피트니스 데이터에 대한 액세스와 모든 기기에서 일관된 기능 동작을 위한 통합된 단일 인터페이스를 제공합니다. 헬스 커넥트를 사용하면 사용자가 기기 내에 건강 및 피트니스 데이터 저장소를 안전하게 보유하면서 액세스 권한을 완전하고 투명하게 제어할 수 있습니다.
헬스 커넥트는 어떻게 작동하나요?
헬스 커넥트는 활동, 수면, 영양, 신체 측정, 활력 징후(예: 심박수, 혈압) 등 50가지가 넘는 일반적인 건강 및 피트니스 데이터 유형과 카테고리를 지원합니다.
사용자 권한을 통해 개발자는 표준화된 스키마와 API 동작을 사용하여 헬스 커넥트에서 안전하게 읽고 쓸 수 있습니다. 사용자는 개인 정보 보호 설정을 완전히 제어할 수 있으며 세부적인 제어를 통해 데이터 액세스를 요청하는 앱을 언제든지 확인할 수 있습니다. 헬스 커넥트의 데이터는 기기에 저장되고 암호화됩니다. 사용자는 기기에서 원하지 않는 데이터 액세스를 차단하거나 데이터를 삭제할 수 있고 여러 앱을 사용할 때 특정 데이터 소스를 다른 데이터 소스보다 우선할 수 있습니다.
헬스 커넥트 아키텍처
다음은 헬스 커넥트의 주요 특징과 아키텍처 구성요소에 관한 설명입니다.
- 클라이언트 앱: 헬스 커넥트와 통합하기 위해 클라이언트 앱은 건강 및 피트니스 앱에 SDK를 연결합니다. 이를 통해 Health Connect API와 상호작용하는 API 노출 영역을 제공합니다.
- 소프트웨어 개발 키트(SDK): SDK를 사용하여 클라이언트 앱이 헬스 커넥트 APK와 통신할 수 있습니다.
- 헬스 커넥트 APK: 헬스 커넥트를 구현하는 APK입니다. 권한 관리 및 데이터 관리 구성요소를 모두 포함합니다. 헬스 커넥트 APK는 사용자 기기에서 직접 사용할 수 있어 헬스 커넥트를 계정 중심이 아닌 기기 중심 환경으로 구성할 수 있습니다.
- 권한 관리: 헬스 커넥트에는 사용자 인터페이스가 포함되어 있으며 이를 통해 앱은 사용자의 권한을 요청하여 데이터를 표시합니다. 헬스 커넥트는 기존 사용자 권한 목록도 제공합니다. 이를 통해 사용자는 다양한 애플리케이션에 부여하거나 거부한 액세스 권한을 관리할 수 있습니다.
- 데이터 관리: 헬스 커넥트는 사용자의 걸음 수나 사이클링 속도, 심박수, 기타 지원되는 데이터 유형 등 기록된 데이터에 관한 개요를 사용자 인터페이스에 제공합니다.
빌드할 항목
이 Codelab에서는 헬스 커넥트와 통합된 간단한 건강 및 피트니스 앱을 빌드합니다. 앱에서 다음 작업을 실행합니다.
- 데이터 액세스를 위한 사용자 권한을 가져오고 확인합니다.
- 헬스 커넥트에 데이터를 씁니다.
- 헬스 커넥트에서 집계된 데이터를 읽습니다.
학습할 내용
- 헬스 커넥트 통합 개발을 지원하도록 환경을 설정하는 방법.
- 권한을 얻고 권한 확인을 실행하는 방법.
- 헬스 커넥트 플랫폼에 건강 및 피트니스 데이터를 제공하는 방법.
- 기기 내 데이터 저장소를 활용하는 방법.
- Google에서 제공하는 개발자 도구로 앱을 확인하는 방법.
필요한 항목
- Android 스튜디오의 최신 안정화 버전
- Android SDK 버전 28(Pie) 이상이 적용된 Android 휴대기기
2. 설정
헬스 커넥트 앱 준비
헬스 커넥트 앱은 애플리케이션이 헬스 커넥트 SDK를 통해 전송하는 모든 요청을 처리합니다. 이러한 요청에는 데이터 저장과 읽기 및 쓰기 액세스 관리가 포함됩니다.
헬스 커넥트에 대한 액세스는 휴대전화에 설치된 Android 버전에 따라 다릅니다. 다음 섹션에서는 최신 Android 버전을 처리하는 방법을 간략히 설명합니다.
Android 14
Android 14(API 수준 34)부터 헬스 커넥트는 Android 프레임워크의 일부입니다. 이 버전의 헬스 커넥트는 프레임워크 모듈이므로 설정이 필요하지 않습니다.
Android 13 및 이전 버전
Android 13(API 수준 33) 이하 버전에서는 헬스 커넥트가 Android 프레임워크의 일부가 아닙니다. 따라서 Google Play 스토어에서 헬스 커넥트 앱을 설치해야 합니다. QR 코드를 스캔하여 헬스 커넥트를 설치하세요.
샘플 코드 가져오기
먼저 GitHub에서 소스 코드를 클론합니다.
git clone https://github.com/android/android-health-connect-codelab.git
샘플 디렉터리에는 이 Codelab의 start
및 finished
코드가 포함되어 있습니다. Android 스튜디오의 Project 뷰에 다음 두 개의 모듈이 있습니다.
start
: 이 프로젝트의 시작 코드로, 이 코드를 변경하여 Codelab을 완료합니다.finished
: 이 Codelab의 완료 코드입니다. 작업 확인에 사용됩니다.
'시작' 코드 살펴보기
Codelab 샘플 앱에는 Jetpack Compose를 사용하여 빌드한 기본 UI가 있으며 포함된 화면은 다음과 같습니다.
WelcomeScreen
: 앱의 방문 페이지이며 헬스 커넥트 사용 가능 여부(설치됨, 설치되지 않음, 지원되지 않음)에 따라 다양한 메시지를 표시합니다.PrivacyPolicyScreen
: 앱의 권한 사용에 관해 설명하며 사용자가 헬스 커넥트 권한 대화상자에서 개인정보처리방침 링크를 클릭하면 사용자에게 표시됩니다.InputReadingsScreen
: 체중 기록을 간단하게 읽고 쓰는 방법을 보여줍니다.ExerciseSessionScreen
: 사용자가 운동 세션을 삽입하고 나열할 수 있는 곳입니다. 기록을 클릭하면 사용자는 세션과 관련된 자세한 데이터가 표시되는ExerciseSessionDetailScreen
으로 이동하게 됩니다.DifferentialChangesScreen
: 변경 토큰을 가져오고 헬스 커넥트에서 새 변경사항을 가져오는 방법을 보여줍니다.
HealthConnectManager
는 헬스 커넥트와 상호작용하는 모든 기능을 저장합니다. 이 Codelab에서는 필수 기능을 완료하는 방법을 단계별로 안내합니다. start
빌드 내의 <!-- TODO:
문자열에는 이 Codelab에서 상응하는 섹션이 있으며 이 섹션에서 프로젝트에 삽입할 수 있는 샘플 코드가 제공됩니다.
먼저 프로젝트에 헬스 커넥트를 추가해 보겠습니다.
헬스 커넥트 클라이언트 SDK 추가
헬스 커넥트 SDK를 사용하려면 build.gradle
파일에 종속 항목을 추가해야 합니다. 헬스 커넥트의 최신 버전을 찾으려면 Jetpack 라이브러리 출시를 확인하세요.
dependencies {
// Add a dependency of Health Connect SDK
implementation "androidx.health.connect:connect-client:1.1.0-alpha10"
}
헬스 커넥트 공개 상태 선언
앱 내에서 Health Connect
와 상호작용하려면 AndroidManifest.xml
에서 다음과 같이 헬스 커넥트 패키지 이름을 선언합니다.
<!-- TODO: declare Health Connect visibility -->
<queries>
<package android:name="com.google.android.apps.healthdata" />
</queries>
시작 프로젝트 실행
설정이 완료되면 start
프로젝트를 실행합니다. 이제 'Health Connect is installed on this device.(헬스 커넥트가 이 기기에 설치되었습니다)'라는 텍스트가 표시된 시작 화면과 메뉴 창이 나타납니다. 이후 섹션에서 헬스 커넥트와 상호작용하는 기능을 추가합니다.
3. 권한 제어
헬스 커넥트에서는 개발자가 권한 요청을 앱에서 사용되는 데이터 유형으로 제한하도록 권장합니다. 포괄적 권한 요청은 앱에 대한 사용자 신뢰도를 떨어뜨리고 사용자 신뢰를 저하시킬 수 있습니다. 권한이 세 번 이상 거부되면 앱이 잠기게 됩니다. 그 결과, 권한 요청이 더 이상 표시되지 않습니다.
이 Codelab에서는 다음 권한만 있으면 됩니다.
- 운동 세션
- 심박수
- 걸음 수
- 총 칼로리 소모량
- 체중
권한 선언
AndroidManifest.xml
권한을 사용하여 앱에서 읽거나 쓰는 모든 데이터 유형을 선언해야 합니다. 헬스 커넥트에서는 버전 1.0.0-alpha10
부터 표준 Android 권한 선언 형식을 사용합니다.
필요한 데이터 유형의 권한을 선언하려면 <uses-permission>
요소를 사용하여 각 이름에 권한을 할당하세요. 그런 다음 <manifest>
태그 내에 중첩합니다. 권한 및 해당 데이터 유형의 전체 목록은 데이터 유형 목록을 참고하세요.
<!-- TODO: Required to specify which Health Connect permissions the app can request -->
<uses-permission android:name="android.permission.health.READ_HEART_RATE"/>
<uses-permission android:name="android.permission.health.WRITE_HEART_RATE"/>
<uses-permission android:name="android.permission.health.READ_STEPS"/>
<uses-permission android:name="android.permission.health.WRITE_STEPS"/>
<uses-permission android:name="android.permission.health.READ_EXERCISE"/>
<uses-permission android:name="android.permission.health.WRITE_EXERCISE"/>
<uses-permission android:name="android.permission.health.READ_TOTAL_CALORIES_BURNED"/>
<uses-permission android:name="android.permission.health.WRITE_TOTAL_CALORIES_BURNED"/>
<uses-permission android:name="android.permission.health.READ_WEIGHT"/>
<uses-permission android:name="android.permission.health.WRITE_WEIGHT"/>
앱에서의 권한 사용 방법을 설명하는 인텐트를 처리하기 위해 AndroidManifest.xml
에서 인텐트 필터를 선언합니다. 앱은 이 인텐트를 처리하고 사용자 데이터의 사용 및 처리 방식을 설명하는 개인정보처리방침을 표시해야 합니다. 이 인텐트는 사용자가 헬스 커넥트 권한 대화상자에서 개인정보처리방침 링크를 클릭하면 앱으로 전송됩니다.
<!-- TODO: Add intent filter to handle permission rationale intent -->
<!-- Permission handling for Android 13 and before -->
<intent-filter>
<action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
</intent-filter>
<!-- Permission handling for Android 14 and later -->
<intent-filter>
<action android:name="android.intent.action.VIEW_PERMISSION_USAGE"/>
<category android:name="android.intent.category.HEALTH_PERMISSIONS"/>
</intent-filter>
이제 앱을 다시 열어 선언된 권한을 확인하세요. 메뉴 창에서 Settings를 클릭하여 헬스 커넥트 설정 화면으로 이동합니다. 그런 다음 App permissions를 클릭하면 목록에 Health Connect Codelab이 표시됩니다. Health Connect Codelab을 클릭하여 해당 앱의 읽기 및 쓰기 액세스 권한에 대한 데이터 유형 목록을 표시합니다.
권한 요청
권한을 관리하기 위해 사용자를 Health Connect Settings로 직접 안내하는 것 외에도 Health Connect API를 통해 앱에서 권한을 요청할 수도 있습니다. 사용자는 언제든지 권한을 변경할 수 있으므로 앱에서 필수 권한을 사용할 수 있는지 확인해야 합니다. 이 Codelab 프로젝트에서는 데이터를 읽거나 쓰기 전에 확인하고 권한 요청을 보냅니다.
HealthConnectClient
는 Health Connect API의 진입점입니다. HealthConnectManager.kt
에서 HealthConnectClient
인스턴스를 가져옵니다.
private val healthConnectClient by lazy { HealthConnectClient.getOrCreate(context) }
애플리케이션 내에서 권한 요청 대화상자를 시작하려면 필요한 데이터 유형의 권한 집합을 먼저 빌드합니다. 사용하는 데이터 유형에 관한 권한을 요청해야 합니다.
예를 들어 Record weight 화면에서는 Weight에 관한 읽기 및 쓰기 권한만 부여해야 합니다. 다음 코드에서와 같이 InputReadingsViewModel.kt
에 권한 세트를 만들었습니다.
val permissions = setOf(
HealthPermission.getReadPermission(WeightRecord::class),
HealthPermission.getWritePermission(WeightRecord::class),
)
그런 다음 권한 요청을 실행하기 전에 이미 권한이 부여되었는지 확인합니다. HealthConnectManager.kt
에서 getGrantedPermissions
를 사용하여 필요한 데이터 유형의 권한이 부여되었는지 확인합니다. 권한 요청을 실행하려면 PermissionController.createRequestPermissionResultContract()
를 사용하여 ActivityResultContract
를 만듭니다. 필요한 권한이 부여되지 않으면 이를 실행해야 합니다.
suspend fun hasAllPermissions(permissions: Set<String>): Boolean {
return healthConnectClient.permissionController.getGrantedPermissions().containsAll(permissions)
}
fun requestPermissionsActivityContract(): ActivityResultContract<Set<String>, Set<String>> {
return PermissionController.createRequestPermissionResultContract()
}
이 Codelab 샘플 앱에서는 필요한 데이터 유형에 관한 권한을 부여하지 않은 경우 화면에 Request permissions 버튼이 표시될 수 있습니다. Request permissions를 클릭하면 헬스 커넥트 권한 대화상자가 열립니다. 필요한 권한을 허용하고 Codelab 앱으로 돌아옵니다.
4. 데이터 쓰기
이제 헬스 커넥트에 기록을 작성해 보겠습니다. Weight 기록을 작성하려면 체중 입력 값으로 WeightRecord
객체를 만듭니다. Health Connect SDK는 다양한 단위 클래스를 지원합니다. Mass.kilograms(weightInput)
을 사용하여 사용자 체중을 킬로그램으로 설정하는 것을 예로 들 수 있습니다.
헬스 커넥트에 기록되는 모든 데이터는 시간대 오프셋 정보를 지정해야 합니다. 데이터를 쓰는 동안 시간대 오프셋 정보를 지정하면 헬스 커넥트에서 데이터를 읽을 때 시간대 정보가 제공됩니다.
체중 기록을 만든 후 healthConnectClient.insertRecords
를 사용하여 헬스 커넥트에 데이터를 씁니다.
/**
* TODO: Writes [WeightRecord] to Health Connect.
*/
suspend fun writeWeightInput(weightInput: Double) {
val time = ZonedDateTime.now().withNano(0)
val weightRecord = WeightRecord(
weight = Mass.kilograms(weightInput),
time = time.toInstant(),
zoneOffset = time.offset
)
val records = listOf(weightRecord)
try {
healthConnectClient.insertRecords(records)
Toast.makeText(context, "Successfully insert records", Toast.LENGTH_SHORT).show()
} catch (e: Exception) {
Toast.makeText(context, e.message.toString(), Toast.LENGTH_SHORT).show()
}
}
이제 앱을 실행해 보겠습니다. Record weight를 클릭하고 새 체중 기록을 킬로그램으로 입력합니다. 체중 기록이 헬스 커넥트에 기록되었는지 확인하려면 Settings에서 헬스 커넥트 앱을 열고 Data and access > Body measurements > Weight > See all entries로 이동합니다. 헬스 커넥트 Codelab에서 작성한 새로운 체중 기록이 표시됩니다.
운동 세션 쓰기
세션은 사용자가 활동을 실행하는 시간 간격입니다. 헬스 커넥트의 운동 세션에는 달리기부터 배드민턴까지 무엇이든 포함될 수 있습니다. 세션을 통해 사용자는 시간 기반 실적을 측정할 수 있습니다. 이 데이터는 일정 기간 동안 측정된 즉각적인 샘플 배열(예: 활동 중 연속 심박수 또는 위치 샘플)을 기록합니다.
다음 예는 운동 세션을 작성하는 방법을 보여줍니다. healthConnectClient.insertRecords
를 사용하여 세션과 연결된 여러 데이터 기록을 삽입합니다. 이 예의 삽입 요청에는 ExerciseType
이 있는 ExerciseSessionRecord
와 걸음 수가 있는 StepsRecord
, Energy
가 있는 TotalCaloriesBurnedRecord
그리고 일련의 HeartRateRecord
샘플이 포함되어 있습니다.
/**
* TODO: Writes an [ExerciseSessionRecord] to Health Connect.
*/
suspend fun writeExerciseSession(start: ZonedDateTime, end: ZonedDateTime) {
healthConnectClient.insertRecords(
listOf(
ExerciseSessionRecord(
startTime = start.toInstant(),
startZoneOffset = start.offset,
endTime = end.toInstant(),
endZoneOffset = end.offset,
exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
title = "My Run #${Random.nextInt(0, 60)}"
),
StepsRecord(
startTime = start.toInstant(),
startZoneOffset = start.offset,
endTime = end.toInstant(),
endZoneOffset = end.offset,
count = (1000 + 1000 * Random.nextInt(3)).toLong()
),
TotalCaloriesBurnedRecord(
startTime = start.toInstant(),
startZoneOffset = start.offset,
endTime = end.toInstant(),
endZoneOffset = end.offset,
energy = Energy.calories((140 + Random.nextInt(20)) * 0.01)
)
) + buildHeartRateSeries(start, end)
)
}
/**
* TODO: Build [HeartRateRecord].
*/
private fun buildHeartRateSeries(
sessionStartTime: ZonedDateTime,
sessionEndTime: ZonedDateTime,
): HeartRateRecord {
val samples = mutableListOf<HeartRateRecord.Sample>()
var time = sessionStartTime
while (time.isBefore(sessionEndTime)) {
samples.add(
HeartRateRecord.Sample(
time = time.toInstant(),
beatsPerMinute = (80 + Random.nextInt(80)).toLong()
)
)
time = time.plusSeconds(30)
}
return HeartRateRecord(
startTime = sessionStartTime.toInstant(),
startZoneOffset = sessionStartTime.offset,
endTime = sessionEndTime.toInstant(),
endZoneOffset = sessionEndTime.offset,
samples = samples
)
}
5. 데이터 읽기
지금까지 Codelab 샘플 앱과 Toolbox 앱을 모두 사용하여 체중과 운동 세션 기록을 작성했습니다. 이제 Health Connect API를 사용하여 이러한 기록을 읽어 보겠습니다. 먼저 ReadRecordsRequest
를 만들고 기록 유형과 읽을 기간을 지정합니다. ReadRecordsRequest
는 dataOriginFilter
를 설정하여 읽으려는 기록의 소스 앱을 지정할 수도 있습니다.
/**
* TODO: Reads in existing [WeightRecord]s.
*/
suspend fun readWeightInputs(start: Instant, end: Instant): List<WeightRecord> {
val request = ReadRecordsRequest(
recordType = WeightRecord::class,
timeRangeFilter = TimeRangeFilter.between(start, end)
)
val response = healthConnectClient.readRecords(request)
return response.records
}
/**
* TODO: Obtains a list of [ExerciseSessionRecord]s in a specified time frame.
*/
suspend fun readExerciseSessions(start: Instant, end: Instant): List<ExerciseSessionRecord> {
val request = ReadRecordsRequest(
recordType = ExerciseSessionRecord::class,
timeRangeFilter = TimeRangeFilter.between(start, end)
)
val response = healthConnectClient.readRecords(request)
return response.records
}
이제 앱을 실행하여 체중 기록 및 운동 세션 목록이 표시되는지 확인해 보겠습니다.
6. 백그라운드에서 데이터 읽기
권한 선언
백그라운드에서 건강 데이터에 액세스하려면 AndroidManifest.xml
파일에서 READ_HEALTH_DATA_IN_BACKGROUND
권한을 선언합니다.
<!-- TODO: Required to specify which Health Connect permissions the app can request -->
...
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND" />
기능 이용 가능 여부 확인
사용자가 최신 버전의 헬스 커넥트를 사용하고 있지 않을 수 있으므로 먼저 기능 사용 가능 여부를 확인하는 것이 좋습니다. 이를 위해 HealthConnectManager.kt
에서 getFeatureStatus
메서드를 사용합니다.
fun isFeatureAvailable(feature: Int): Boolean{
return healthConnectClient
.features
.getFeatureStatus(feature) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE
}
ExerciseSessionViewModel.kt
의 백그라운드 읽기 기능은 FEATURE_READ_HEALTH_DATA_IN_BACKGROUND
상수를 사용하여 확인합니다.
backgroundReadAvailable.value = healthConnectManager.isFeatureAvailable(
HealthConnectFeatures.FEATURE_READ_HEALTH_DATA_IN_BACKGROUND
)
권한 요청
백그라운드 읽기 기능을 사용할 수 있는지 확인한 후 운동 세션 화면에서 백그라운드 읽기 요청을 클릭하여 PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND 권한을 요청할 수 있습니다.
사용자에게 다음과 같은 메시지가 표시됩니다.
사용자는 시스템 설정에서 헬스 커넥트 > 앱 권한 > 헬스 커넥트 Codelab > 추가 액세스로 이동하여 백그라운드 읽기 액세스 권한을 부여할 수도 있습니다.
백그라운드에서 데이터 읽기
WorkManager
를 사용하여 백그라운드 작업을 예약합니다. 백그라운드에서 걸음 수 읽기 버튼을 탭하면 10초 지연 후 앱에서 ReadStepWorker
를 시작합니다. 이 worker는 헬스 커넥트에서 지난 24시간 동안의 총 걸음 수를 가져옵니다. 그런 다음 Logcat에 이 정보를 자세히 설명하는 유사한 로그 항목이 표시됩니다.
There are 4000 steps in Health Connect in the last 24 hours.
7. 차등 데이터 읽기
Health Connect Differential Changes API는 데이터 유형 세트에 관한 특정 시점의 변경사항을 추적하는 데 도움이 됩니다. 적절하게 데이터베이스를 업데이트할 수 있도록 사용자가 앱 외부의 기존 기록을 업데이트했는지 또는 삭제했는지를 확인하려는 경우를 예로 들 수 있습니다.
헬스 커넥트를 통한 데이터 읽기는 포그라운드에서 실행되는 애플리케이션으로 제한됩니다. 이 제한사항은 사용자 개인 정보 보호를 더욱 강화하기 위해 마련되었습니다. 이를 통해 헬스 커넥트는 사용자 데이터에 대한 백그라운드 읽기 액세스 권한이 없고 포그라운드에서만 데이터를 읽고 액세스할 수 있음을 사용자에게 알리고 보장합니다. 앱이 포그라운드에 있을 때 Differential Changes API를 사용하면 개발자가 변경 토큰을 배포하여 헬스 커넥트 변경사항을 가져올 수 있습니다.
HealthConnectManager.kt
에는 두 가지 함수 getChangesToken()
과 getChanges()
가 있으며 이러한 함수에 Differential Changes API를 추가하여 데이터 변경사항을 가져옵니다.
초기 변경 토큰 설정
데이터 변경사항은 앱에서 변경 토큰을 사용하여 요청하는 경우에만 헬스 커넥트에서 가져옵니다. 변경 토큰은 차등 데이터를 가져올 커밋 기록의 지점을 나타냅니다.
변경 토큰을 가져오려면 데이터 변경사항을 추적하려는 데이터 유형 세트와 함께 ChangesTokenRequest
를 전송합니다. 토큰을 유지하고 헬스 커넥트에서 업데이트를 가져오려고 할 때 이 토큰을 사용하세요.
/**
* TODO: Obtains a Changes token for the specified record types.
*/
suspend fun getChangesToken(): String {
return healthConnectClient.getChangesToken(
ChangesTokenRequest(
setOf(
ExerciseSessionRecord::class
)
)
)
}
변경 토큰으로 데이터 업데이트
앱이 마지막으로 헬스 커넥트와 동기화된 시점부터 변경사항을 가져오려면 이전에 가져온 변경 토큰을 사용하고 이 토큰과 함께 getChanges
호출을 전송합니다. ChangesResponse
는 헬스 커넥트에서 관찰된 변경사항(예: UpsertionChange
및 DeletionChange
) 목록을 반환합니다.
/**
* TODO: Retrieve changes from a Changes token.
*/
suspend fun getChanges(token: String): Flow<ChangesMessage> = flow {
var nextChangesToken = token
do {
val response = healthConnectClient.getChanges(nextChangesToken)
if (response.changesTokenExpired) {
throw IOException("Changes token has expired")
}
emit(ChangesMessage.ChangeList(response.changes))
nextChangesToken = response.nextChangesToken
} while (response.hasMore)
emit(ChangesMessage.NoMoreChanges(nextChangesToken))
}
이제 앱을 실행하여 Changes 화면으로 이동합니다. 먼저 Track changes를 사용 설정하여 변경 토큰을 가져옵니다. 그런 다음 Toolbox 또는 Codelab 앱에서 체중 또는 운동 세션을 삽입합니다. Changes 화면으로 다시 돌아가 Get new changes를 선택합니다. 이제 업데이트 변경사항이 표시됩니다.
8. 데이터 합산
헬스 커넥트는 집계 API를 통해 집계된 데이터도 제공합니다. 다음 예는 헬스 커넥트에서 누적 및 통계 데이터를 가져오는 방법을 보여줍니다.
healthConnectClient.aggregate
를 사용하여 AggregateRequest
를 전송합니다. 집계 요청에서 집계 측정항목 세트와 가져올 기간을 지정합니다. 예를 들어 ExerciseSessionRecord.EXERCISE_DURATION_TOTAL
및 StepsRecord.COUNT_TOTAL
은 누적 데이터를 제공하는 반면 WeightRecord.WEIGHT_AVG
, HeartRateRecord.BPM_MAX
, HeartRateRecord.BPM_MIN
은 통계 데이터를 제공합니다.
/**
* TODO: Returns the weekly average of [WeightRecord]s.
*/
suspend fun computeWeeklyAverage(start: Instant, end: Instant): Mass? {
val request = AggregateRequest(
metrics = setOf(WeightRecord.WEIGHT_AVG),
timeRangeFilter = TimeRangeFilter.between(start, end)
)
val response = healthConnectClient.aggregate(request)
return response[WeightRecord.WEIGHT_AVG]
}
다음 예는 특정 운동 세션의 관련 집계 데이터를 가져오는 방법을 보여줍니다. 먼저 uid
와 함께 healthConnectClient.readRecord
를 사용하여 기록을 읽습니다. 그런 다음 운동 세션의 startTime
과 endTime
을 기간으로 사용하고 dataOrigin
을 필터로 사용하여 관련 집계를 읽습니다.
/**
* TODO: Reads aggregated data and raw data for selected data types, for a given [ExerciseSessionRecord].
*/
suspend fun readAssociatedSessionData(
uid: String,
): ExerciseSessionData {
val exerciseSession = healthConnectClient.readRecord(ExerciseSessionRecord::class, uid)
// Use the start time and end time from the session, for reading raw and aggregate data.
val timeRangeFilter = TimeRangeFilter.between(
startTime = exerciseSession.record.startTime,
endTime = exerciseSession.record.endTime
)
val aggregateDataTypes = setOf(
ExerciseSessionRecord.EXERCISE_DURATION_TOTAL,
StepsRecord.COUNT_TOTAL,
TotalCaloriesBurnedRecord.ENERGY_TOTAL,
HeartRateRecord.BPM_AVG,
HeartRateRecord.BPM_MAX,
HeartRateRecord.BPM_MIN,
)
// Limit the data read to just the application that wrote the session. This may or may not
// be desirable depending on the use case: In some cases, it may be useful to combine with
// data written by other apps.
val dataOriginFilter = setOf(exerciseSession.record.metadata.dataOrigin)
val aggregateRequest = AggregateRequest(
metrics = aggregateDataTypes,
timeRangeFilter = timeRangeFilter,
dataOriginFilter = dataOriginFilter
)
val aggregateData = healthConnectClient.aggregate(aggregateRequest)
val heartRateData = readData<HeartRateRecord>(timeRangeFilter, dataOriginFilter)
return ExerciseSessionData(
uid = uid,
totalActiveTime = aggregateData[ExerciseSessionRecord.EXERCISE_DURATION_TOTAL],
totalSteps = aggregateData[StepsRecord.COUNT_TOTAL],
totalEnergyBurned = aggregateData[TotalCaloriesBurnedRecord.ENERGY_TOTAL],
minHeartRate = aggregateData[HeartRateRecord.BPM_MIN],
maxHeartRate = aggregateData[HeartRateRecord.BPM_MAX],
avgHeartRate = aggregateData[HeartRateRecord.BPM_AVG],
heartRateSeries = heartRateData,
)
}
이제 앱을 실행하여 Record weight 화면에 평균 체중이 표시되는지 확인해 보세요. Exercise sessions 화면을 열고 운동 세션 기록 중 하나를 선택하여 운동 세션의 세부 데이터를 확인할 수도 있습니다.
9. 축하합니다
축하합니다. 첫 번째 헬스 커넥트 통합 건강 및 피트니스 앱을 빌드했습니다.
앱은 권한을 선언하고 앱에 사용되는 데이터 유형에 관한 사용자 권한을 요청할 수 있습니다. 또한 헬스 커넥트 데이터 저장소에서 데이터를 읽고 쓸 수 있습니다. 헬스 커넥트 데이터 저장소에 모의 데이터를 만들어 앱 개발을 지원하기 위해 헬스 커넥트 도구 상자를 사용하는 방법도 배웠습니다.
지금까지 건강 및 피트니스 앱을 헬스 커넥트 생태계의 일부로 만드는 데 필요한 주요 단계를 알아봤습니다.