寫入資料

本指南將介紹在 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。因此,您必須為該項目手動設定較高的值。

最佳做法

建構邏輯後,建議您在寫入或更新資料時遵循最佳做法