세션

헬스 커넥트에서 세션은 사용자가 활동을 실행하는 시간 간격입니다. SleepSessionRecordExerciseSessionRecord 데이터 유형은 모두 세션입니다.

세션을 통해 사용자는 연속 심박수나 위치 데이터와 같은 일정 기간 동안의 시간 기반 성능을 측정할 수 있습니다.

ExerciseSessionRecord 세션에는 달리기부터 배드민턴까지 다양한 활동이 포함됩니다.

SleepSessionRecord 세션에는 AWAKE, SLEEPING, DEEP 등 수면 단계를 기록하는 데이터가 포함됩니다.

하위유형 데이터는 세션에 '속하는' 데이터로, 상위 세션(예: 수면 단계, 운동 세그먼트)과 함께 읽을 때만 의미가 있습니다.

연결된 데이터는 다른 세션(예: 걸음 수, 심박수)과 별도로 또는 함께 읽을 수 있는 Record 데이터입니다.

일반 안내

다음은 헬스 커넥트에서 세션으로 작업하는 방법에 관한 권장사항 가이드라인입니다.

  • 세션은 특정 운동이나 활동의 데이터를 추가하거나 수면을 위해 사용해야 합니다.
suspend fun writeExerciseSession(healthConnectClient: HealthConnectClient) {
    healthConnectClient.insertRecords(
        listOf(
            ExerciseSessionRecord(
                startTime = Instant.parse("2022-05-10T10:00:00.000Z"),
                startZoneOffset = ZoneOffset.of("-08:00"),
                endTime = Instant.parse("2022-05-10T11:00:00.000Z"),
                endZoneOffset = ZoneOffset.of("-08:00"),
                exerciseType = ExerciseSessionRecord.ExerciseType.WALKING,
                title = "My Walk"
            ),
            StepsRecord(
                startTime = Instant.parse("2022-05-10T10:00:00.000Z"),
                startZoneOffset = ZoneOffset.of("-08:00"),
                endTime = Instant.parse("2022-05-10T10:30:00.000Z"),
                endZoneOffset = ZoneOffset.of("-08:00"),
                count = 2800
            ),
StepsRecord(
                startTime = Instant.parse("2022-05-10T10:30:00.000Z"),
                startZoneOffset = ZoneOffset.of("-08:00"),
                endTime = Instant.parse("2022-05-10T11:00:00.000Z"),
                endZoneOffset = ZoneOffset.of("-08:00"),
                count = 3200
            ),  
        )
    )
}
  • 세션은 일일 걸음 수와 같은 일반적인 측정에 사용하면 안 됩니다.
  • 하위유형 데이터에는 UID가 없지만 연결된 데이터에는 고유한 UID가 있습니다.
  • 하위유형 데이터는 세션에서 겹치지 않는 순차적 타임스탬프를 사용하여 정렬되어야 합니다. 간격은 허용됩니다.
  • 세션은 사용자가 데이터를 계속 기록하기보다는 세션과 연결하고 세션의 일부로 추적하려는 경우에 유용합니다.

수면 세션

헬스 커넥트에서 수면 데이터를 읽거나 쓸 수 있습니다. 수면 데이터는 세션으로 표시되며 8가지 고유한 수면 단계로 나눌 수 있습니다.

  • UNKNOWN: 사용자가 수면 중인지 지정되지 않았거나 알 수 없습니다.
  • AWAKE: 사용자가 낮이 아닌 수면 주기 내에서 깨어 있습니다.
  • SLEEPING: 일반적이거나 상세하지 않은 수면 설명입니다.
  • OUT_OF_BED: 사용자가 수면 세션 중에 침대에서 나옵니다.
  • AWAKE_IN_BED: 사용자가 침대에서 깨어 있습니다.
  • LIGHT: 사용자가 얕은 수면 주기에 있습니다.
  • DEEP: 사용자가 깊은 수면 주기에 있습니다.
  • REM: 사용자가 렘수면 주기에 있습니다.

이러한 값은 시간 범위 내에서 사용자가 경험하는 수면 유형을 나타냅니다. 수면 단계 작성은 선택사항이지만 가능한 경우 권장합니다.

수면 단계 유무와 관계없이 수면 세션 작성

SleepSessionRecord 데이터 유형은 두 부분으로 구성됩니다.

  1. 전체 수면 시간을 아우르는 전체 세션
  2. 수면 세션 중의 개별 단계(예: 얕은 수면 또는 깊은 수면)

단계 없이 수면 세션을 삽입하는 방법은 다음과 같습니다.

      SleepSessionRecord(
        title = "weekend sleep",
        startTime = startTime,
        endTime = endTime,
        startZoneOffset = ZoneOffset.UTC,
        endZoneOffset = ZoneOffset.UTC,
      )

수면 세션의 전체 기간을 포함하는 단계를 추가하는 방법은 다음과 같습니다.

val stages = listOf(
    SleepSessionRecord.Stage(
        startTime = START_TIME
        endTime = END_TIME,
        stage = SleepSessionRecord.STAGE_TYPE_SLEEPING,
    )
)

SleepSessionRecord(
        title = "weekend sleep",
        startTime = START_TIME,
        endTime = END_TIME,
        startZoneOffset = START_ZONE_OFFSET,
        endZoneOffset = END_ZONE_OFFSET,
        stages = stages,
      )
  }

수면 세션 읽기

반환된 모든 수면 세션에 대해 수면 단계 데이터도 있는지 확인해야 합니다.

suspend fun readSleepSessions(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response =
        healthConnectClient.readRecords(
            ReadRecordsRequest(
                SleepSessionRecord::class,
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
    for (sleepRecord in response.records) {
        // Retrieve relevant sleep stages from each sleep record
        val sleepStages = sleepRecord.stages
    }
}

수면 세션 삭제

다음은 세션을 삭제하는 방법입니다. 이 예에서는 수면 세션을 사용했습니다.

suspend fun deleteSleepSession(
    healthConnectClient: HealthConnectClient,
    sleepRecord: SleepSessionRecord,
) {
    val timeRangeFilter = TimeRangeFilter.between(sleepRecord.startTime, sleepRecord.endTime)
    healthConnectClient.deleteRecords(SleepSessionRecord::class, timeRangeFilter)
}

운동 세션

운동 세션에는 달리기부터 배드민턴까지 무엇이든 포함될 수 있습니다.

운동 세션 작성

세션이 포함된 삽입 요청을 빌드하는 방법은 다음과 같습니다.

suspend fun writeExerciseSession(healthConnectClient: HealthConnectClient) {
    healthConnectClient.insertRecords(
        listOf(
            ExerciseSessionRecord(
                startTime = START_TIME,
                startZoneOffset = START_ZONE_OFFSET,
                endTime = END_TIME,
                endZoneOffset = END_ZONE_OFFSET,
                exerciseType = ExerciseSessionRecord.ExerciseType.RUNNING,
                title = "My Run"
            ),
            DistanceRecord(
                startTime = START_TIME,
                startZoneOffset = START_ZONE_OFFSET,
                endTime = END_TIME,
                endZoneOffset = END_ZONE_OFFSET,
                distance = 5000.meters
            ),
            // ... other records
        )
    )
}

이전 예에서 레코드는 전체 세션 기간에 걸쳐 있는 Distance에 추가되지만 데이터는 다른 세부사항으로 추가될 수 있다는 점에 유의하세요.

앱이 달리기 중에 규칙적으로 이동 거리를 측정했다면 또 다른 접근 방식은 각각 달리기의 일부로 포함된 거리를 나타내는 여러 이동 거리 레코드를 포함하는 것입니다.

운동 세션 읽기

다음은 운동 세션을 읽는 방법을 보여주는 예입니다.

suspend fun readExerciseSessions(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response =
        healthConnectClient.readRecords(
            ReadRecordsRequest(
                ExerciseSessionRecord::class,
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
    for (exerciseRecord in response.records) {
        // Process each exercise record
        // Optionally pull in with other data sources of the same time range.
        val distanceRecord =
            healthConnectClient
                .readRecords(
                    ReadRecordsRequest(
                        DistanceRecord::class,
                        timeRangeFilter =
                            TimeRangeFilter.between(
                                exerciseRecord.startTime,
                                exerciseRecord.endTime
                            )
                    )
                )
                .records
    }
}

하위유형 데이터 쓰기

세션은 추가 정보고 세션을 보강하는 비필수 하위유형 데이터로 구성될 수도 있습니다.

예를 들어 운동 세션에는 ExerciseSegment, ExerciseLap, ExerciseRoute 클래스가 포함될 수 있습니다.

val segments = listOf(
  ExerciseSegment(
    startTime = Instant.parse("2022-01-02T10:10:10Z"),
    endTime = Instant.parse("2022-01-02T10:10:13Z"),
    segmentType = ActivitySegmentType.BENCH_PRESS,
    repetitions = 373
  )
)

val laps = listOf(
  ExerciseLap(
    startTime = Instant.parse("2022-01-02T10:10:10Z"),
    endTime = Instant.parse("2022-01-02T10:10:13Z"),
    length = 0.meters
  )
)

ExerciseSessionRecord(
  exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_CALISTHENICS,
    startTime = Instant.parse("2022-01-02T10:10:10Z"),
    endTime = Instant.parse("2022-01-02T10:10:13Z"),
  startZoneOffset = ZoneOffset.UTC,
  endZoneOffset = ZoneOffset.UTC,
  segments = segments,
  laps = laps,
  route = route
)

운동 세션 삭제

운동 세션을 삭제하는 방법은 두 가지가 있습니다.

  1. 기간별
  2. UID별

기간에 따라 하위유형 데이터를 삭제하는 방법은 다음과 같습니다.

suspend fun deleteExerciseSession(
    healthConnectClient: HealthConnectClient,
    exerciseRecord: ExerciseSessionRecord,
) {
    val timeRangeFilter = TimeRangeFilter.between(sleepRecord.startTime, sleepRecord.endTime)
    healthConnectClient.deleteRecords(SleepSessionRecord::class, timeRangeFilter)
    // delete the associated distance record
    healthConnectClient.deleteRecords(DistanceRecord::class, timeRangeFilter)
}

UID로 하위유형 데이터를 삭제할 수도 있습니다. 그러나 이렇게 하면 운동 세션만 삭제되고 관련 데이터는 삭제되지 않습니다.

suspend fun deleteExerciseSession(
    healthConnectClient: HealthConnectClient,
    exerciseRecord: ExerciseSessionRecord,
) {
    healthConnectClient.deleteRecords(
        ExerciseSessionRecord::class,
        recordIdsList = listOf(exerciseRecord.metadata.id),
        clientRecordIdsList = emptyList()
    )
}