工作階段

在 Health Connect 中,時段是指使用者執行活動的一段時間間隔。SleepSessionRecordExerciseSessionRecord 資料類型都屬於時段。

使用者可利用時段,在一段時間內依據時間來評估成效,例如連續心率或位置資料。

ExerciseSessionRecord 時段包含各種活動,例如跑步、打羽毛球等。

SleepSessionRecord 時段包含記錄睡眠階段的資料,例如 AWAKESLEEPINGDEEP

子類型資料是「屬於」時段的資料,而且只在與睡眠階段、運動時段等父項時段一併讀取時才有意義。

關聯資料是指可單獨讀取或與其他時段一併讀取的 Record 資料,例如步數、心率。

一般指南

以下提供一些最佳做法指南,說明如何在 Health Connect 中使用時段。

  • 時段應用於新增來自特定健身運動或活動的資料,或針對睡眠的資料:
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。
  • 子類型資料必須符合時段中不重疊的序列時間戳記,不過可以出現間隔。
  • 如果使用者想將資料與時段建立關聯 並以時段的形式加以追蹤,而非持續記錄資料,這時就適合使用時段。

睡眠週期

您可以在 Health Connect 中讀取或寫入睡眠資料。睡眠資料會顯示為時段,並且可分為 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
    }
}

寫入子類型資料

時段也可以包含非必要的子類型資料,運用額外資訊提供更豐富的時段資料。

舉例來說,運動時段可包含 ExerciseSegmentExerciseLapExerciseRoute 類別:

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()
    )
}