データを書き込む

このガイドでは、ヘルスコネクトでデータの書き込みまたは更新を行うプロセスについて説明します。

データ構造を設定する

データを書き込む前に、まずレコードを設定する必要があります。50 を超えるデータ型があり、各データ型にそれぞれの構造があります。使用可能なデータ型について詳しくは、Jetpack リファレンスをご覧ください。

基本のレコード

ヘルスコネクトの Steps データ型には、各読み取りの間にユーザーが歩いた歩数が記録されます。歩数は、健康、フィットネス、ウェルネスのプラットフォームで共通の測定値を表します。

次の例は、歩数データを設定する方法を示しています。

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

測定単位を含むレコード

ヘルスコネクトでは、精度を高めるため、測定単位とともに値を格納できます。その一例が、広範囲を包括的にカバーする Nutrition データ型です。総炭水化物からビタミンまで、さまざまな栄養素項目が対象に含まれます。各データポイントは、食事または食品の一部として摂取された可能性のある栄養素を表します。

Nutrition データ型では、すべての栄養素が Mass の単位で表現され、energyEnergy の単位で表現されます。

次の例は、バナナを食べたユーザーの栄養データを設定する方法を示しています。

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
)

系列データを含むレコード

ヘルスコネクトでは系列データのリストを格納できます。その一例が、読み取り間に検出された一連の心拍数のサンプルをキャプチャする Heart Rate データ型です。

このデータ型では、パラメータ 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(),
        )
    }
)

データを書き込む

ヘルスコネクトの一般的なワークフローとして、データの書き込みがあります。レコードを追加するには、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
    }
}

データを更新する

1 つ以上のレコードを変更する必要がある場合、特にアプリのデータストアをヘルスコネクトのデータと同期する必要がある場合は、データを更新できます。既存のデータを更新するには、レコードの検索に使用される ID に応じて 2 つの方法があります。

メタデータ

データを更新するときに必要になるため、最初に Metadata クラスを確認することをおすすめします。作成時、ヘルスコネクトの各 Record には metadata フィールドがあります。同期に関連するプロパティは次のとおりです。

プロパティ 説明
id ヘルスコネクトの各 Record には一意の id 値があります。
ヘルスコネクトでは、 新しいレコードを挿入するときに、この値が自動的に設定されます。
lastModifiedTime Record にはレコードの最終更新日時も記録されます。
この値はヘルスコネクトによって自動的に入力されます。
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 とクライアント レコード バージョンの値を使用している場合は、updateRecords ではなく insertRecords を使用することをおすすめします。

insertRecords 関数を使用するとデータをアップサートできます。指定されたクライアント レコード ID のセットに基づくデータがヘルスコネクトに存在する場合、データは上書きされます。存在しない場合は、新しいデータとして書き込まれます。このシナリオは、アプリのデータストアからヘルスコネクトにデータを同期する必要がある場合に便利です。

次の例は、アプリのデータストアから取得されたデータに対してアップサートを実行する方法を示しています。

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

クライアント レコード バージョンの値のチェック

データをアップサートするプロセスにクライアント レコード バージョンが含まれている場合、ヘルスコネクトは clientRecordVersion 値の比較チェックを行います。挿入されるデータのバージョンが既存のデータのバージョンよりも高い場合は、アップサートが行われます。それ以外の場合は、この変更は無視され、値は同じままになります。

データにバージョニングを含めるには、バージョニングのロジックに基づいて Metadata.clientRecordVersionLong 値を指定する必要があります。

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

Upsert は、データが予期せず上書きされるのを防ぐため、変更が発生しても version を自動更新しません。そのため、今より大きな値を手動で指定する必要があります。

データ書き込みのベスト プラクティス

アプリは、独自のソースのデータのみをヘルスコネクトに書き込む必要があります。

アプリのデータが別のアプリからインポートされたものである場合、そのデータをヘルスコネクトに書き込む役割はインポート元のアプリが担います。

また、境界外のデータや内部システムエラーなどの書き込み例外を処理するロジックを実装することもおすすめします。バックオフと再試行の戦略は、ジョブ スケジューリング メカニズムに適用できます。ヘルスコネクトへの書き込みが最終的に失敗した場合でも、アプリは必要な処理を引き続き行える状態でなければなりません。診断に役立てるため、必ずエラーをログに記録して報告してください。

データをトラッキングする場合、アプリがデータを書き込む方法に応じて、いくつかの推奨事項があります。

パッシブ トラッキング

これには、受動的なフィットネス管理または健康管理を行うアプリ(たとえば、バックグラウンドで歩数や心拍数を継続的に記録するアプリ)が含まれます。

アプリは以下の方式でヘルスコネクトに定期的にデータを書き込む必要があります。

  • 同期のたびに、新しいデータと、前回の同期の後で変更された更新データのみを書き込みます。
  • 1 回の書き込みリクエストのレコード数を最大 1,000 個にしてリクエストをチャンクします。
  • WorkManager を使用して、定期的なバックグラウンド タスクを少なくとも 15 分の期間にスケジュール設定します。
  • デバイスがアイドル状態でバッテリー残量が十分にある場合にのみタスクを実行するよう制限します。

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

アクティブ トラッキング

これには、エクササイズや睡眠などのイベントベースのトラッキングを行うアプリや、栄養などの手動のユーザー入力を行うアプリが含まれます。これらのレコードは、アプリがフォアグラウンドにある場合、または 1 日に数回使用されるまれなイベントの場合に作成されます。

イベント期間全体を通じて、アプリでヘルスコネクトの実行が維持されないようにします。

データは、次の 2 つの方法のいずれかを使って、ヘルスコネクトに書き込む必要があります。

  • イベントの完了後にデータをヘルスコネクトに同期します。たとえば、トラッキング対象のエクササイズ セッションが終了したときにデータを同期します。
  • WorkManager を使用して、1 回限りのタスクのデータを後で同期するようにスケジュール設定します。

書き込みの粒度と頻度に関するベスト プラクティス

ヘルスコネクトにデータを書き込むときは、適切な解像度を使用します。適切な解像度を使用することで、データの一貫性と正確性を維持しながら、ストレージの負荷を軽減できます。データ解決には以下の 2 つのものが含まれます。

  1. 書き込み頻度: アプリケーションがヘルスコネクトに新しいデータを push する頻度。たとえば、15 分ごとに新しいデータを書き込みます。
  2. 書き込まれるデータの粒度: push されるデータがサンプリングされる頻度。たとえば、5 秒ごとに心拍数のサンプルを書き込むことができます。すべてのデータ型に同じサンプルレートが必要なわけではありません。歩数データを 1 秒ごとに更新してもメリットはほとんどありません。60 秒などの頻度ではありません。ただし、サンプルレートが高いほど、ユーザーは健康とフィットネスのデータをより詳細かつ細かく確認できます。サンプルレートの頻度は、詳細とパフォーマンスのバランスをとれるように設定する必要があります。

1 日を通じてモニタリングされるデータを書き込む

歩数など、継続的に収集されるデータの場合、アプリはその日に少なくとも 15 分ごとにヘルスコネクトに書き込む必要があります。

データの種類

単位

予定

手順

1 分ごと

23:14 ~ 23:15 - 5 ステップ

23:16 ~ 23:17 - 22 ステップ

23:17 ~ 23:18 - 8 ステップ

歩数のケイデンス

歩/分

1 分ごと

23:14 ~ 23:15 ~ 5 spm

23:16 ~ 23:17 ~ 22 spm

23:17 ~ 23:18 ~ 8 秒

車椅子を押した回数

プッシュ

1 分ごと

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 カロリー

総消費カロリー

kcal

15分毎

23:15 - 23:30 - 16 kcal

23:30 - 23:45 - 16 kcal

23:45 - 00:00 - 16 kcal

距離

km/分

1 分ごと

23:14 ~ 23:15 ~ 0.008 km

23:16 ~ 23:16 - 0.021 km

23:17 ~ 23:18 - 0.012 km

獲得標高

m

1 分ごと

20:36 ~ 20:37 - 3.048 分

20:39 ~ 20:40 ~ 3.048 分

23:23 ~ 23:24 - 9.144 分

上った階数

1 分ごと

23:14 - 23:15 - 5 階

23:16 - 23:16 - 22 階

23:17 - 23:18 - 8 階

心拍数

bpm

1 分ごと

午前 6:11 - 55 bpm

心拍変動 Rmssd

ミリ秒

1 分ごと

午前 6:11 ~ 23 ミリ秒

呼吸数

呼吸/分

1 分ごと

23:14 - 23:15 - 60 呼吸/分

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

23:17 - 23:18 - 64 呼吸/分

血中酸素ウェルネス

%

1 時間ごと

6:11 ~ 95.208%

セッションを書き込む

データは、ワークアウトまたは睡眠セッションの終了時にヘルスコネクトに書き込む必要があります。

睡眠セッションやエクササイズ セッションは、記録デバイスと適切なメタデータ(RecordingMethod など)を使用して書き込むことをおすすめします。

少なくとも、アプリケーションは下記の「想定される」列のガイダンスに従う必要があります。可能であれば、「最適」なガイダンスに従ってください。

エクササイズ中に記録されたデータ

データの種類

単位

予定

今後ともどうぞよろしくお願いいたします。

手順

1 分ごと

1 秒ごと

23:14 ~ 23:15 - 5 ステップ

23:16 ~ 23:17 - 22 ステップ

23:17 ~ 23:18 - 8 ステップ

歩数のケイデンス

歩/分

1 分ごと

1 秒ごと

23:14 ~ 23:15 ~ 35 秒

23:16 ~ 23:17 ~ 37 spm

23:17 ~ 23:18 ~ 40 spm

車椅子を押した回数

プッシュ

1 分ごと

1 秒ごと

23:14 ~ 23:15 - 5 回

23:16 ~ 23:17 - 22 プッシュ

23:17 ~ 23:18 - 8 回

サイクリングペダリングケイデンス

RPM

1 分ごと

1 秒ごと

23:14 ~ 23:15 ~ 65 rpm

23:16 ~ 23:17 ~ 70 rpm

23:17 ~ 23:18 ~ 68 rpm

電力

ワット

1 分ごと

1 秒ごと

23:14 ~ 23:15 - 250 ワット

23:16 ~ 23:17 - 255 ワット

23:17 ~ 23:18 - 245 ワット

速度

km/分

1 分ごと

1 秒ごと

23:14 ~ 23:15 - 0.3 km/分

23:16 ~ 23:17 - 0.4 km/分

23:17 ~ 23:18 -0.4 km/分

距離

km/m

1 分ごと

1 秒ごと

23:14 ~ 23:15 ~ 0.008 km

23:16 ~ 23:16 - 0.021 km

23:17 ~ 23:18 - 0.012 km

アクティブな消費カロリー

kcal

1 分ごと

1 秒ごと

23:14 ~ 23:15 - 20 kcal

23:16 - 23:17 - 20 kcal

23:17 - 23:18 - 25 kcal

総消費カロリー

kcal

1 分ごと

1 秒ごと

23:14 ~ 23:15 - 36 kcal

23:16 - 23:17 - 36 kcal

23:17 - 23:18 - 41 kcal

獲得標高

m

1 分ごと

1 秒ごと

20:36 ~ 20:37 - 3.048 分

20:39 ~ 20:40 ~ 3.048 分

23:23 ~ 23:24 - 9.144 分

ExerciseRoutes

緯度/経度/Alt

3 ~ 5 秒ごと

1 秒ごと

心拍数

bpm

1 分ごと

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

1 日の 1 つの値(朝の最初に想定されるもの)

午前 6:11 - 60 bpm

血中酸素ウェルネス

%

1 日の 1 つの値(朝の最初に想定されるもの)

6:11 ~ 95.208%