데이터 쓰기

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

데이터 구조 설정

데이터를 쓰기 전에 먼저 레코드를 설정해야 합니다. 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을 자동으로 증분하지 않으므로 예상치 못하게 데이터를 덮어쓰는 경우가 방지됩니다. 그 때문에 더 높은 값을 수동으로 제공해야 합니다.

권장사항

로직을 구성한 후에는 데이터를 쓰거나 업데이트할 때 권장사항을 따르는 것이 좋습니다.