데이터 쓰기

이 가이드에서는 헬스 커넥트에서 데이터를 쓰거나 업데이트하는 프로세스를 다룹니다.

데이터 구조 설정

데이터를 쓰기 전에 먼저 레코드를 설정해야 합니다. 50개가 넘는 각 데이터 유형은 저마다의 구조가 있습니다. 사용 가능한 데이터 유형에 관한 자세한 내용은 Jetpack 참조를 확인하세요.

기본 레코드

헬스 커넥트의 걸음 수 데이터 유형은 측정 시점과 시점 사이에 사용자가 걸은 걸음 수를 포착합니다. 걸음 수는 건강, 피트니스, 웰빙 플랫폼에서 공통으로 측정되는 수치를 나타냅니다.

다음 예는 걸음 수 데이터를 설정하는 방법을 보여줍니다.

val stepsRecord = StepsRecord(
    count = 120,
    startTime = START_TIME,
    endTime = END_TIME,
    startZoneOffset = START_ZONE_OFFSET,
    endZoneOffset = END_ZONE_OFFSET
)

측정 단위가 포함된 레코드

헬스 커넥트는 정확성을 제공하기 위해 측정 단위와 함께 값을 저장할 수 있습니다. 한 가지 예는 방대하고 포괄적인 영양 데이터 유형입니다. 여기에는 총 탄수화물에서 비타민에 이르기까지 선택할 수 있는 영양소 필드가 다양하게 포함되어 있습니다. 각 데이터 포인트는 식사나 음식의 일부로 섭취했을 가능성이 있는 영양소를 나타냅니다.

이 데이터 유형에서 모든 영양소는 Mass의 단위로 표현되는 반면, energyEnergy의 단위로 표현됩니다.

다음 예는 바나나를 먹은 사용자의 영양 데이터를 설정하는 방법을 보여줍니다.

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
)

연속 데이터가 포함된 레코드

헬스 커넥트는 연속 데이터 목록을 저장할 수 있습니다. 한 가지 예는 측정값 간에 감지된 일련의 하트비트 샘플을 캡처하는 심박수 데이터 유형입니다.

이 데이터 유형에서 매개변수 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(),
        )
    }
)

데이터 쓰기

헬스 커넥트의 일반적인 워크플로 중 하나는 데이터 쓰기입니다. 레코드를 추가하려면 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
    }
}

데이터 업데이트

레코드를 하나 이상 변경해야 하는 경우, 특히 앱 데이터 스토어를 헬스 커넥트의 데이터와 동기화해야 하는 경우 데이터를 업데이트하면 됩니다. 레코드를 찾는 데 사용되는 식별자에 따라 기존 데이터를 업데이트하는 방법에는 두 가지가 있습니다.

메타데이터

데이터를 업데이트할 때 필요하므로 Metadata 클래스를 먼저 살펴보는 것이 좋습니다. 생성 시 헬스 커넥트의 각 Record에는 metadata 필드가 있습니다. 다음은 동기화와 관련된 속성입니다.

속성 설명
id 헬스 커넥트의 모든 Record에는 고유한 id 값이 있습니다.
새 레코드를 삽입할 때 헬스 커넥트에서 자동으로 이를 채웁니다.
lastModifiedTime 또한 모든 Record는 레코드가 마지막으로 수정된 시간을 추적합니다.
헬스 커넥트에서 자동으로 이를 채웁니다.
clientRecordId Record에는 앱의 데이터 스토어에서 참조 역할을 하는 고유 ID가 연결될 수 있습니다.
앱에서 이 값을 제공합니다.
clientRecordVersion 레코드에 clientRecordId가 있는 경우 앱의 데이터 스토어에서 데이터를 버전과 동기화할 수 있도록 clientRecordVersion을 사용할 수 있습니다.
앱에서 이 값을 제공합니다.

레코드 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
    }
}

클라이언트 레코드 ID를 통해 upsert

선택사항인 클라이언트 레코드 ID와 클라이언트 레코드 버전 값을 사용하는 경우 updateRecords 대신 insertRecords를 사용하는 것이 좋습니다.

insertRecords 함수에는 데이터를 upsert할 수 있는 기능이 있습니다. 지정된 클라이언트 레코드 ID 집합을 기반으로 데이터가 헬스 커넥트에 존재하는 경우 데이터를 덮어씁니다. 그렇지 않으면 새 데이터로 작성됩니다. 이 시나리오는 앱 데이터 스토어에서 헬스 커넥트로 데이터를 동기화해야 할 때마다 유용합니다.

다음 예는 앱 데이터 스토어에서 가져온 데이터에 대해 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())

클라이언트 레코드 버전의 값 확인

데이터 upsert 프로세스에 클라이언트 레코드 버전이 포함되어 있으면 헬스 커넥트는 clientRecordVersion 값에서 비교 검사를 실행합니다. 삽입된 데이터의 버전이 기존 데이터의 버전보다 높으면 upsert가 발생합니다. 그렇지 않으면 변경사항을 무시하고 값이 동일하게 유지됩니다.

데이터에 버전 관리를 포함하려면 버전 관리 로직에 따라 Metadata.clientRecordVersionLong 값을 제공해야 합니다.

val sr = StepsRecord(
    count = count,
    startTime = startTime,
    startZoneOffset = startZoneOffset,
    endTime = endTime,
    endZoneOffset = endZoneOffset,
    metadata = Metadata(
        clientRecordId = cid,
        clientRecordVersion = version
    )
)

upsert는 변경이 있을 때마다 version을 자동으로 증분하지 않으므로 예상치 못하게 데이터를 덮어쓰는 경우가 방지됩니다. 그 때문에 더 높은 값을 수동으로 제공해야 합니다.

데이터 쓰기 권장사항

앱은 자체 공급된 데이터만 헬스 커넥트에 써야 합니다.

앱의 데이터를 다른 앱에서 가져온 경우 데이터를 헬스 커넥트에 쓰는 것에 대한 책임은 데이터를 소유한 다른 앱에 있습니다.

데이터가 경계 밖에 있을 때 발생하는 오류 또는 내부 시스템 오류와 같은 쓰기 예외를 처리하는 로직을 구현하는 것도 좋습니다. 작업 예약 메커니즘에서 백오프 및 재시도 전략을 적용할 수 있습니다. 헬스 커넥트로의 쓰기 작업이 최종적으로 실패하면 앱이 그 내보내기 지점을 지나서 이동할 수 있어야 합니다. 오류를 기록하고 보고하여 진단을 돕는 것을 잊지 마세요.

데이터를 추적할 때 앱이 데이터를 쓰는 방식에 따라 몇 가지 추천사항이 있습니다.

수동 추적

여기에는 백그라운드에서 지속적으로 걸음 수나 심박수를 기록하는 것과 같이 피트니스 활동 또는 건강 관련 항목을 수동으로 추적하는 앱이 포함됩니다.

앱은 다음과 같은 방법으로 헬스 커넥트에 주기적으로 데이터를 기록해야 합니다.

  • 동기화할 때마다 새 데이터와 마지막 동기화 이후에 수정된 업데이트된 데이터만 씁니다.
  • 쓰기 요청 하나당 최대 1,000개의 레코드를 묶어서 요청합니다.
  • WorkManager를 사용하여 기간이 15분 이상인 백그라운드 작업을 주기적으로 예약합니다.
  • 기기가 유휴 상태이고 배터리 잔량이 충분한 경우에만 실행되도록 작업을 제한합니다.

    val constraints = Constraints.Builder()
        .requiresBatteryNotLow()
        .requiresDeviceIdle(true)
        .build()
    
    val writeDataWork = PeriodicWorkRequestBuilder<WriteDataToHealthConnectWorker>(
            15,
            TimeUnit.MINUTES,
            5,
            TimeUnit.MINUTES
        )
        .setConstraints(constraints)
        .build()
    

능동 추적

여기에는 운동 및 수면과 같은 이벤트 기반 추적 또는 영양과 같은 직접적인 사용자 입력을 실행하는 앱이 포함됩니다. 이러한 기록은 앱이 포그라운드에 있거나 드물게 하루에 몇 번 사용되는 경우에 생성됩니다.

앱은 이벤트의 전체 기간 동안 헬스 커넥트가 계속 실행되지 않도록 해야 합니다.

다음 두 가지 방법 중 하나로 데이터를 헬스 커넥트에 써야 합니다.

  • 이벤트가 완료된 후에 헬스 커넥트에 데이터를 동기화합니다. 예를 들어 사용자가 추적 중인 운동 세션을 종료할 때 데이터를 동기화합니다.
  • 나중에 데이터를 동기화하려면 WorkManager를 사용하여 일회성 작업을 예약합니다.

쓰기의 세부사항 및 빈도에 대한 권장사항

헬스 커넥트에 데이터를 쓸 때 적절한 해상도를 사용합니다. 적절한 해상도를 사용하면 일관되고 정확한 데이터를 유지하면서 스토리지 부하를 줄일 수 있습니다. 데이터 확인에는 다음 두 가지가 포함됩니다.

  1. 쓰기 빈도: 애플리케이션이 새 데이터를 헬스 커넥트에 푸시하는 빈도입니다. 예를 들어 15분마다 새 데이터를 씁니다.
  2. 기록된 데이터의 세부사항: 푸시된 데이터가 샘플링된 빈도입니다. 예를 들어 심박수 샘플을 5초마다 작성합니다. 모든 데이터 유형에 동일한 샘플링 레이트가 필요한 것은 아닙니다 걸음 수 데이터를 업데이트하는 경우 매초 업데이트하는 것은 비교적 덜 자주(예: 60초) 업데이트하는 것보다 이득이 없습니다. 하지만 샘플링 레이트가 높을수록 사용자가 자신의 건강/피트니스 데이터를 더 상세하고 세부적으로 확인할 수 있습니다. 샘플링 레이트 빈도는 세부정보와 성능 간에 균형을 유지해야 합니다.

하루 종일 모니터링하는 데이터를 작성합니다.

걸음 수와 같이 지속적으로 수집되는 데이터의 경우 애플리케이션은 최소한 하루 15분마다 헬스 커넥트에 써야 합니다.

데이터 유형

단위

예상

걸음수

걸음 수

1분마다

23:14 - 23:15 - 5단계

23:16 - 23:17 - 22걸음

23:17 - 23:18 - 8걸음

걸음 수 주기

걸음 수/분

1분마다

23:14 ~ 23:15 - 5 spm

23:16 ~ 23:17 - 22 spm

23:17 ~ 23:18 - 8spm

휠체어 밀기

푸시

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 칼로리

총칼로리 소모량

kcal

15분마다

23:15 - 23:30 - 16 kcal

23:30 ~ 23:45 - 16 kcal

23:45 - 00:00 - 16 kcal

거리

km/분

1분마다

23:14~23:15~0.008km

23:16~23:16~0.021km

23:17~23:18~0.012km

상승 고도

m

1분마다

20:36~20:37~3.048m

20:39~20:40~3.048m

23:23 ~ 23:24 - 9.144m

오른 층수

1분마다

23:14 - 23:15 - 5층

23:16 - 23:16 - 22층

23:17 - 23:18 - 8층

심박수

BPM

1분마다

오전 6:11 - 55 bpm

HeartRateVariabilityRmssd

ms

1분마다

오전 6:11 - 23 ms

호흡수

분당 호흡수

1분마다

23:14 - 23:15 - 호흡 60회/분

23:16 - 23:16 - 분당 호흡 62회

23:17 - 23:18 - 64회/분

산소포화도

%

1시간마다

6:11~95.208%

세션 쓰기

데이터는 운동 또는 수면 세션이 끝날 때 헬스 커넥트에 기록되어야 합니다.

모든 수면 세션이나 운동 세션은 기록 기기 및 RecordingMethod를 포함한 적절한 메타데이터로 작성하는 것이 좋습니다.

최소한 신청서는 아래 '예상' 열의 안내를 따라야 합니다. 가능하면 '가장 적합한' 안내를 따르세요.

운동 중 모니터링되는 데이터

데이터 유형

단위

예상

감사합니다.

걸음수

걸음 수

1분마다

1초마다

23:14~23:15 - 5단계

23:16 - 23:17 - 22걸음

23:17 - 23:18 - 8걸음

걸음 수 주기

걸음 수/분

1분마다

1초마다

23:14~23:15~35spm

23:16 ~ 23:17 - 37 spm

23:17 ~ 23:18 - 40 spm

휠체어 밀기

푸시

1분마다

1초마다

23:14-23:15 - 푸시 5회

23:16 - 23:17 - 푸시 22개

23:17 - 23:18 - 푸시 8개

사이클링페달링케이던스

rpm

1분마다

1초마다

23:14~23:15~65rpm

23:16~23:17~70rpm

23:17 ~ 23:18 - 68rpm

출력

와트

1분마다

1초마다

23:14~23:15 - 250와트

23:16 - 23:17 - 255와트

23:17 - 23:18 - 245와트

속도

km/분

1분마다

1초마다

23:14~23:15~0.3km/분

23:16~23:17 - 0.4km/분

23:17 - 23:18 -0.4km/분

거리

km/m

1분마다

1초마다

23:14~23:15~0.008km

23:16~23:16~0.021km

23:17~23:18~0.012km

활성칼로리 소모량

kcal

1분마다

1초마다

23:14~23:15 - 20kcal

23:16 - 23:17 - 20kcal

23:17 - 23:18 - 25 kcal

총칼로리 소모량

kcal

1분마다

1초마다

23:14~23:15 - 36kcal

23:16 - 23:17 - 36kcal

23:17 - 23:18 - 41 kcal

상승 고도

m

1분마다

1초마다

20:36~20:37~3.048m

20:39~20:40~3.048m

23:23 ~ 23:24 - 9.144m

운동 경로

위도/경도/Alt

3~5초마다

1초마다

심박수

BPM

1분마다

1초마다

23:14~23:15~150bpm

23:16 ~ 23:17 -152bpm

23:17 ~ 23:18 - 155bpm

수면 중 모니터링된 데이터

데이터 유형

단위

예상 샘플

수면 준비

무대

수면 단계별 세부 기간

23:46 ~ 23:50 - 깨어남

23:50 ~ 23:56 - 얕은 수면

23:56 - 00:16 - 깊은 수면

안정시 심박수

BPM

단일 일일 값 (아침에 첫날 예상)

오전 6:11 - 60 bpm

산소포화도

%

단일 일일 값 (아침에 첫날 예상)

6:11~95.208%