寫入資料

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

設定資料結構

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

基本記錄

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

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

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

含有測量單位的記錄

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

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

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

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
)

含有系列資料的記錄

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

在這個資料類型中,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(),
        )
    }
)

寫入資料

Health Connect 中常見的一項工作流程就是寫入資料。如要新增記錄,請使用 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
    }
}

更新資料

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

Metadata

建議您先檢查 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)
        }

        client.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(
        // 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())

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

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

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

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

為防止意外覆寫資料的情況,每當變更發生時,更新/插入作業不會自動依累加原則設定 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 步

步頻

步/分鐘

每分鐘

23:14 - 23:15 - 5 秒

下午 23:16 - 23:17 - 22

下午 23:17 - 23:18 - 8 秒

推動輪椅次數

推送

每分鐘

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 卡路里

卡路里燃燒總量

大卡

每隔 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 公里

爬升高度

分鐘

每分鐘

20:36 - 20:37 - 3.048 公尺

20:39 - 20:40 - 3.048 公尺

23:23 - 23:24 - 9.144 公尺

攀爬樓層數

層樓

每分鐘

23:14 - 23:15 - 5 層樓

23:16 - 23:16 - 22 層樓

23:17 - 23:18 - 8 層樓

心率

bpm

每分鐘

06:11 - 55 bpm

心率變異基因段

毫秒

每分鐘

上午 6:11 - 23 毫秒

呼吸速率

呼吸/分鐘

每分鐘

23:14 - 23:15 - 60 次呼吸

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

23:17 - 23:18 - 64 次呼吸

血氧濃度

%

每小時

6:11 - 95.208%

寫入工作階段

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

根據最佳做法,所有睡眠時段或運動時段應使用記錄裝置及適當的中繼資料 (包括 RecordingMethod) 寫入。

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

運動時追蹤的資料

資料類型

單位

預期中

祝一切順心!

範例

操作步驟

步數

每分鐘

每 1 秒

23:14-23:15 - 5 步

23:16 - 23:17 - 22 步

23:17 - 23:18 - 8 步

步頻

步/分鐘

每分鐘

每 1 秒

下午 23:14-23:15 - 35

下午 23:16 - 23:17 - 37

下午 23:17 - 23:18 - 40

推動輪椅次數

推送

每分鐘

每 1 秒

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

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

23:17 - 23:18 - 8 下推式

自行車踩踏頻率

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 W

23:17 - 23:18 - 245 W

速度

公里/分鐘

每分鐘

每 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 公里

活動卡路里燃燒量

大卡

每分鐘

每 1 秒

23:14-23:15 - 20 大卡

23:16 - 23:17 - 20 大卡

23:17 - 23:18 - 25 大卡

卡路里燃燒總量

大卡

每分鐘

每 1 秒

23:14-23:15 - 36 大卡

23:16 - 23:17 - 36 大卡

23:17 - 23:18 - 41 大卡

爬升高度

分鐘

每分鐘

每 1 秒

20:36 - 20:37 - 3.048 公尺

20:39 - 20:40 - 3.048 公尺

23:23 - 23:24 - 9.144 公尺

運動路線

經緯度/alt

每 3 到 5 秒

每 1 秒

心率

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 - 深層睡眠

靜止心率

bpm

單一每日價值 (早上一晚預計要推出的項目)

06:11 - 60 bpm

血氧濃度

%

單一每日價值 (早上一晚預計要推出的項目)

6:11 - 95.208%