寫入資料

本指南適用於 Health Connect 1.1.0-alpha12 版

本指南將介紹在 Health Connect 中寫入或更新資料的程序。

設定資料結構

在寫入資料之前,我們需要先設定記錄。資料類型有超過 50 種,每種都有各自的結構。如要進一步瞭解可用的資料類型,請參閱 Jetpack 參考資料

基本記錄

Health Connect 中的「步數」資料類型會擷取使用者在兩次讀取作業間的步數。步數是各大健康與健身平台上的常見測量指標。

以下範例說明如何設定步數資料:

val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofMinutes(15))

val stepsRecord = StepsRecord(
    count = 120,
    startTime = startTime,
    endTime = endTime,
    startZoneOffset = ZoneOffset.UTC,
    endZoneOffset = ZoneOffset.UTC,
    metadata = Metadata.autoRecorded(
        device = Device(type = Device.TYPE_WATCH)
    )
)

含有測量單位的記錄

Health Connect 可以儲存值及其測量單位,因此能提供準確資料。舉例來說,「營養」資料類型相當龐大且全面,包含各種選用的營養素欄位,從碳水化合物總量到維生素應有盡有。每個資料點都代表可能作為膳食或食品的一部分攝入的營養素。

在這個資料類型中,所有營養素均以 Mass 為單位,而 energy 則以 Energy 為單位。

以下範例說明如何針對吃了香蕉的使用者設定營養資料:

val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofMinutes(1))

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 = startTime,
    endTime = endTime,
    startZoneOffset = ZoneOffset.UTC,
    endZoneOffset = ZoneOffset.UTC,
    metadata = Metadata.manualEntry(
        device = Device(type = Device.TYPE_PHONE)
    )
)

含有系列資料的記錄

Health Connect 可儲存一系列資料的清單。舉例來說,「心率」資料類型會擷取系統在讀取作業間偵測到的一系列心跳資料樣本。

在這個資料類型中,samples 參數會以心率樣本清單表示。每個樣本都包含 beatsPerMinute 值和 time 值。

以下範例說明如何設定心率系列資料:

val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofMinutes(5))

val heartRateRecord = HeartRateRecord(
    startTime = startTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = endTime,
    endZoneOffset = ZoneOffset.UTC,
    // records 10 arbitrary data, to replace with actual data
    samples = List(10) { index ->
        HeartRateRecord.Sample(
            time = startTime + Duration.ofSeconds(index.toLong()),
            beatsPerMinute = 100 + index.toLong(),
        )
    },
    metadata = Metadata.autoRecorded(
        device = Device(type = Device.TYPE_WATCH)
    ))

寫入資料

Health Connect 中常見的一項工作流程就是寫入資料。如要新增記錄,請使用 insertRecords

以下範例說明如何透過插入步數來寫入資料:

suspend fun insertSteps(healthConnectClient: HealthConnectClient) {
    val endTime = Instant.now()
    val startTime = endTime.minus(Duration.ofMinutes(5))
    try {
        val stepsRecord = StepsRecord(
            count = 120,
            startTime = startTime,
            endTime = endTime,
            startZoneOffset = ZoneOffset.UTC,
            endZoneOffset = ZoneOffset.UTC,
            metadata = Metadata.autoRecorded(
                device = Device(type = Device.TYPE_WATCH)
            )
        )
        healthConnectClient.insertRecords(listOf(stepsRecord))
    } catch (e: Exception) {
        // Run error handling here
    }
}

更新資料

如果您需要變更一或多筆記錄,特別是在需要將應用程式資料儲存庫與 Health Connect 的資料同步時,您就可以更新資料。更新現有資料的方法有兩種,至於要採取哪一種,則視用於尋找記錄的 ID 而定。

中繼資料

建議您先檢查 Metadata 類別,因為這是更新資料前的必要操作。Health Connect 中的每個 Record 在建立時都包含 metadata 欄位。下列屬性與同步處理相關:

屬性 說明
id Health Connect 中的每筆 Record 都有專屬的 id 值。
在插入新記錄時 ,Health Connect 會自動填入這項資料
lastModifiedTime 每筆 Record 也會追蹤上次修改記錄的時間。
Health Connect 會自動填入這項資料。
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)
        }

        healthConnectClient.updateRecords(newStepsRecords)
    } catch (e: Exception) {
        // Run error handling here
    }
}

透過用戶端記錄 ID 更新/插入

如果您使用選用的用戶端記錄 ID 和用戶端記錄版本值,我們會建議您使用 insertRecords,而非 updateRecords

insertRecords 函式可更新/插入資料。如果 Health Connect 中的資料以指定的一組用戶端記錄 ID 為依據,系統會覆寫這類資料。但如果不是的話,則會以新資料的形式寫入。當您需要將應用程式資料儲存庫中的資料同步到 Health Connect 時,這就非常實用。

以下範例說明如何對從應用程式資料儲存庫提取的資料執行更新/插入作業:

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(
        metadata = Metadata.autoRecorded(
            clientRecordId = "Your client record ID",
            device = Device(type = Device.TYPE_WATCH)
        ),
        // Assign more parameters for this record
    )
    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())

檢查用戶端記錄版本中的值

如果您在更新/插入資料的程序中也會處理到用戶端記錄版本,Health Connect 會對 clientRecordVersion 值執行比較檢查。假如插入資料的版本高於現有資料版本,系統就會執行更新/插入作業。但如果不是的話,該程序會忽略變更,而值也會保持不變。

如要在資料中加入版本編號,您需要依據版本編號邏輯為 Metadata.clientRecordVersion 提供 Long 值。

val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofMinutes(15))

val stepsRecord = StepsRecord(
    count = 100L,
    startTime = startTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = endTime,
    endZoneOffset = ZoneOffset.UTC,
    metadata = Metadata.manualEntry(
        clientRecordId = "Your supplied record ID",
        clientRecordVersion = 0L, // Your supplied record version
        device = Device(type = Device.TYPE_WATCH)
    )
)

為防止意外覆寫資料的情況,每當變更發生時,更新/插入作業不會自動依累加原則設定 version。因此,您必須手動為該項目輸入較高的值。

寫入資料的最佳做法

應用程式只能將「擁有來源」的資料寫入 Health Connect。

如果應用程式資料是從另一個應用程式匯入,則應由該應用程式負責將其擁有的資料寫入 Health Connect。

此外,建議您針對資料寫入例外狀況導入處理邏輯,例如資料在邊界外或發生內部系統錯誤時。您可以對工作排程機制套用輪詢和重試策略。如果最終無法順利寫入 Health Connect,請確保應用程式能夠移出該匯出點。請務必記錄並回報錯誤,以利診斷作業。

追蹤資料時,您可以根據應用程式寫入資料的方式採用以下幾項建議。

被動追蹤

這包括提供被動健身或健康追蹤功能的應用程式,例如在背景持續記錄步數或心率。

應用程式需採用以下做法,定期將資料寫入 Health Connect:

  • 每次同步時,請僅寫入新資料及上次同步後修改的更新資料。
  • 在每個寫入要求中,區塊要求最多為 1000 條記錄。
  • 使用 WorkManager 安排週期性背景工作,時間長度至少為 15 分鐘。
  • 請限制只在裝置處於閒置狀態且電量充足時執行工作。

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

主動追蹤

這類應用程式功能包括執行以運動和睡眠等事件為基礎的追蹤功能,或讓使用者手動輸入營養攝取等資訊。如果應用程式是在前景運作,或事件發生頻率相當低 (如一天幾次),就會建立這類記錄。

請確保在整個事件期間,應用程式不會要求 Health Connect 保持在執行狀態。

資料必須透過以下其中一種方式寫入 Health Connect:

  • 在事件完成後,將資料同步處理至 Health Connect。例如在使用者結束追蹤的運動時段後同步處理資料。
  • 使用 WorkManager 排定一次性工作,稍後再同步處理資料。

寫入精細程度和頻率的最佳做法

將資料寫入 Health Connect 時,請使用適當的解析度。使用適當的解析度有助於減少儲存空間負載,同時維持一致且準確的資料。資料解決方案包含 2 個部分:

  1. 寫入頻率:應用程式將任何新資料推送至 Health Connect 的頻率。例如,每隔 15 分鐘寫入新資料。
  2. 寫入資料的精細程度:推送的資料被取樣的頻率。例如,每隔 5 秒寫入心率樣本。並非所有資料類型都需要相同的取樣率。如要更新步數資料,每秒取樣一次的效果不會優於採用較低的取樣頻率,例如每 60 秒一次。不過,取樣率較高可讓使用者更詳細瞭解自己的健康與健身資料。您應在精細程度和效能之間取得平衡,採用適當的取樣頻率。

寫入全天監控的資料

如果是持續收集的資料 (例如步數),應用程式應至少每天每 15 分鐘寫入一次 Health Connect。

資料類型

單位

預期

示例

步數

步數

每分鐘

23:14 - 23:15 - 5 個步驟

23:16 - 23:17 - 22 步

23:17 - 23:18 - 8 個步驟

StepsCadence

步/分鐘

每分鐘

23:14 - 23:15 - 5 spm

23:16 - 23:17 - 22 spm

23:17 - 23:18 - 8 spm

推動輪椅次數

推送

每分鐘

23:14 - 23:15 - 5 次推送

23:16 - 23:17 - 22 次推送

23:17 - 23:18 - 8 次推送

ActiveCaloriesBurned

卡路里

每 15 分鐘檢查一次

23:15 - 23:30 - 2 卡路里

23:30 - 23:45 - 25 卡路里

23:45 - 00:00 - 5 卡路里

TotalCaloriesBurned

卡路里

每 15 分鐘檢查一次

23:15 - 23:30 - 16 卡路里

23:30 - 23:45 - 16 卡路里

23:45 - 00:00 - 16 卡路里

距離

公里/分鐘

每分鐘

23:14-23:15 - 0.008 公里

23:16 - 23:16 - 0.021 公里

23:17 - 23:18 - 0.012 公里

ElevationGained

分鐘

每分鐘

20:36 - 20:37 - 3.048m

20:39 - 20:40 - 3.048m

23:23 - 23:24 - 9.144m

FloorsClimbed

層樓

每分鐘

23:14 - 23:15 - 5 層樓

23:16 - 23:16 - 22 層樓

23:17 - 23:18 - 8 層樓

HeartRate

bpm

每分鐘

上午 6 點 11 分 - 55 bpm

HeartRateVariabilityRmssd

ms

每分鐘

上午 6 點 11 分 - 23 毫秒

RespiratoryRate

呼吸次數/分鐘

每分鐘

23:14 - 23:15 - 60 次/分鐘

23:16 - 23:16 - 62 次/分鐘

23:17 - 23:18 - 64 次/分鐘

OxygenSaturation

%

每小時

6:11 - 95.208%

寫入時段

資料應在健身或睡眠時段結束時寫入 Health Connect。

最佳做法是,任何睡眠或運動時段都應使用錄製裝置和適當的中繼資料 (包括 RecordingMethod) 來寫入。

您的應用程式至少應遵循下方「預期」欄中的指引。盡可能遵循「最佳」指南。

運動期間追蹤的資料

資料類型

單位

預期

祝一切順心!

示例

步數

步數

每分鐘

每 1 秒

23:14-23:15 - 5 個步驟

23:16 - 23:17 - 22 步

23:17 - 23:18 - 8 個步驟

StepsCadence

步/分鐘

每分鐘

每 1 秒

23:14-23:15 - 35 spm

23:16 - 23:17 - 37 spm

23:17 - 23:18 - 40 spm

推動輪椅次數

推送

每分鐘

每 1 秒

23:14-23:15 - 5 次推送

23:16 - 23:17 - 22 次推送

23:17 - 23:18 - 8 次推送

CyclingPedalingCadence

rpm:每分鐘呼吸次數

每分鐘

每 1 秒

23:14-23:15 - 65 rpm

23:16 - 23:17 - 70 rpm

23:17 - 23:18 - 68 rpm

電源

瓦特

每分鐘

每 1 秒

23:14-23:15 - 250 瓦

23:16 - 23:17 - 255 瓦

23:17 - 23:18 - 245 瓦

速度

公里/分鐘

每分鐘

每 1 秒

23:14-23:15 - 0.3 公里/分鐘

23:16 - 23:17 - 0.4 公里/分鐘

23:17 - 23:18 -0.4 公里/分鐘

距離

公里/公尺

每分鐘

每 1 秒

23:14-23:15 - 0.008 公里

23:16 - 23:16 - 0.021 公里

23:17 - 23:18 - 0.012 公里

ActiveCaloriesBurned

卡路里

每分鐘

每 1 秒

23:14-23:15 - 20 卡路里

23:16 - 23:17 - 20 卡路里

23:17 - 23:18 - 25 卡路里

TotalCaloriesBurned

卡路里

每分鐘

每 1 秒

23:14-23:15 - 36 卡路里

23:16 - 23:17 - 36 卡路里

23:17 - 23:18 - 41 卡路里

ElevationGained

分鐘

每分鐘

每 1 秒

20:36 - 20:37 - 3.048m

20:39 - 20:40 - 3.048m

23:23 - 23:24 - 9.144m

ExerciseRoutes

lat/lng/alt

每 3 到 5 秒

每 1 秒

HeartRate

bpm

每分鐘

每 1 秒

23:14-23:15 - 150 bpm

23:16 - 23:17 -152 bpm

23:17 - 23:18 - 155 bpm

睡眠期間追蹤的資料

資料類型

單位

預期的樣本

示例

睡眠分期

階段

各睡眠階段的精細時間長度

23:46 - 23:50 - 清醒

23:50 - 23:56 - 淺層睡眠

23:56 - 00:16 - 熟睡

RestingHeartRate

bpm

單一每日值 (預計在早上第一時間)

上午 6 點 11 分 - 60 bpm

OxygenSaturation

%

單一每日值 (預計在早上第一時間)

6:11 - 95.208%