History API を使用すると、アプリはフィットネス ストアに対して一括操作を実行できます。 健康とウェルネスに関する履歴データの読み取り、挿入、更新、削除 History API を使用して、次のことを行います。
- 他の方法を使って挿入または記録された健康とウェルネスに関するデータを読み取る 。
- バッチデータを Google Fit にインポートします。
- Google Fit のデータを更新します。
- アプリが以前に保存した履歴データを削除します。
セッション メタデータを含むデータを挿入するには、 Sessions API。
データを読み取る
以降のセクションでは、さまざまな種類の集計データを読み取る方法について説明します。
詳細データと集計データを読み取る
過去のデータを読み取るには、
DataReadRequest
構成されます
Kotlin
// Read the data that's been collected throughout the past week. val endTime = LocalDateTime.now().atZone(ZoneId.systemDefault()) val startTime = endTime.minusWeeks(1) Log.i(TAG, "Range Start: $startTime") Log.i(TAG, "Range End: $endTime") val readRequest = DataReadRequest.Builder() // The data request can specify multiple data types to return, // effectively combining multiple data queries into one call. // This example demonstrates aggregating only one data type. .aggregate(DataType.AGGREGATE_STEP_COUNT_DELTA) // Analogous to a "Group By" in SQL, defines how data should be // aggregated. // bucketByTime allows for a time span, whereas bucketBySessi<on allows // bucketing by a >href=&qu<ot>;/fit/android/using-sessions"sessions/a. .bucketByTime(1, TimeUnit.DAYS) .setTimeRange(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS) .build()
Java
// Read the data that's been collected throughout the past week. ZonedDateTime endTime = LocalDateTime.now().atZone(ZoneId.systemDefault()); ZonedDateTime startTime = endTime.minusWeeks(1); Log.i(TAG, "Range Start: $startTime"); Log.i(TAG, "Range End: $endTime"); DataReadRequest readRequest = new DataReadRequest.Builder() // The data request can specify multiple data types to return, // effectively combining multiple data queries into one call. // This example demonstrates aggregating only one data type. .aggregate(DataType.AGGREGATE_STEP_COUNT_DELTA) // Analogous to a "Group By" in SQL, defines how data should be // aggregated. // bucketByTime allows for a time span, while bucketBySession allows // bucketing by sessions. .bucketByTime(1, TimeUnit.DAYS) .setTimeRange(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS) .build();
前の例では、集計されたデータポイントを使用しています。各 DataPoint
1 日の歩数を表します。この特定のユースケースでは
2 つの利点があります。
- アプリとフィットネス ストアが交換するデータの量は少なくなっています。
- アプリでデータを手動で集計する必要はありません。
複数のアクティビティ タイプのデータを集計する
アプリでは、データ リクエストを使用してさまざまな種類のデータを取得できます。「
次の例は、BigQuery の
DataReadRequest
の範囲内で行った各アクティビティの消費カロリーを取得
表示されます。得られたデータは、1 活動あたりのカロリーと次のように一致します。
各アクティビティに個別のバケットが割り当てられる
カロリーデータを抽出できます。
Kotlin
val readRequest = DataReadRequest.Builder() .aggregate(DataType.AGGREGATE_CALORIES_EXPENDED) .bucketByActivityType(1, TimeUnit.SECONDS) .setTimeRange(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS) .build()
Java
DataReadRequest readRequest = new DataReadRequest.Builder() .aggregate(DataType.AGGREGATE_CALORIES_EXPENDED) .bucketByActivityType(1, TimeUnit.SECONDS) .setTimeRange(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS) .build();
DataReadRequest
インスタンスを作成したら、
HistoryClient.readData()
メソッドを使用し、過去のデータを非同期で読み取ることができます。
次の例は、DataPoint
インスタンスを取得する方法を示しています。
DataSet
:
Kotlin
Fitness.getHistoryClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions)) .readData(readRequest) .addOnSuccessListener { response -> // The aggregate query puts datasets into buckets, so flatten into a // single list of datasets for (dataSet in response.buckets.flatMap { it.dataSets }) { dumpDataSet(dataSet) } } .addOnFailureListener { e -> Log.w(TAG,"There was an error reading data from Google Fit", e) } fun dumpDataSet(dataSet: DataSet) { Log.i(TAG, "Data returned for Data type: ${dataSet.dataType.name}") for (dp in dataSet.dataPoints) { Log.i(TAG,"Data point:") Log.i(TAG,"\tType: ${dp.dataType.name}") Log.i(TAG,"\tStart: ${dp.getStartTimeString()}") Log.i(TAG,"\tEnd: ${dp.getEndTimeString()}") for (field in dp.dataType.fields) { Log.i(TAG,"\tField: ${field.name.toString()} Value: ${dp.getValue(field)}") } } } fun DataPoint.getStartTimeString() = Instant.ofEpochSecond(this.getStartTime(TimeUnit.SECONDS)) .atZone(ZoneId.systemDefault()) .toLocalDateTime().toString() fun DataPoint.getEndTimeString() = Instant.ofEpochSecond(this.getEndTime(TimeUnit.SECONDS)) .atZone(ZoneId.systemDefault()) .toLocalDateTime().toString()
Java
Fitness.getHistoryClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions)) .readData(readRequest) .addOnSuccessListener (response -> { // The aggregate query puts datasets into buckets, so convert to a // single list of datasets for (Bucket bucket : response.getBuckets()) { for (DataSet dataSet : bucket.getDataSets()) { dumpDataSet(dataSet); } } }) .addOnFailureListener(e -> Log.w(TAG, "There was an error reading data from Google Fit", e)); } private void dumpDataSet(DataSet dataSet) { Log.i(TAG, "Data returned for Data type: ${dataSet.dataType.name}"); for (DataPoint dp : dataSet.getDataPoints()) { Log.i(TAG,"Data point:"); Log.i(TAG,"\tType: ${dp.dataType.name}"); Log.i(TAG,"\tStart: ${dp.getStartTimeString()}"); Log.i(TAG,"\tEnd: ${dp.getEndTimeString()}"); for (Field field : dp.getDataType().getFields()) { Log.i(TAG,"\tField: ${field.name.toString()} Value: ${dp.getValue(field)}"); } } } private String getStartTimeString() { return Instant.ofEpochSecond(this.getStartTime(TimeUnit.SECONDS)) .atZone(ZoneId.systemDefault()) .toLocalDateTime().toString(); } private String getEndTimeString() { return Instant.ofEpochSecond(this.getEndTime(TimeUnit.SECONDS)) .atZone(ZoneId.systemDefault()) .toLocalDateTime().toString(); }
1 日の合計データを読み取る
Google Fit では、1 日あたりの合計日数も簡単に
データタイプを指定します。こちらの
HistoryClient.readDailyTotal()
メソッドを使用し、現在の時刻の午前 0 時時点で指定したデータ型
日付(デバイスの現在のタイムゾーン)たとえば、
1 日の合計を取得するには、TYPE_STEP_COUNT_DELTA
データ型をこのメソッドに追加します。
できます。日別の集計がある瞬間的なデータ型を渡すことができます。
確認できます。サポートされるデータ型の詳細については、このモジュールの
DataType.getAggregateType
。
Google Fit に登録するための認証は必要ありません
HistoryClient.readDailyTotal()
からの最新情報 TYPE_STEP_COUNT_DELTA
件
メソッドがデフォルトのアカウントを使用して呼び出され、
scopes が指定されている。
これは、走行できない地域で歩数データを必要とする場合に便利です。
Wear OS のウォッチフェイスなどに権限パネルを表示します。
ユーザーは Google Fit アプリで一貫した歩数を好みます。
その他のアプリ、Wear OS ウォッチフェイスなどです。これにより、
一貫した信頼性の高いエクスペリエンスを提供できます。歩数を一定に保つには、
アプリまたはウォッチフェイスから Google Fit プラットフォームで行った手順
新しい Pod の数を
onExitAmbient()
。
このデータをウォッチフェイスで使用する方法の詳細については、以下をご覧ください。
ウォッチフェイスの追加機能
Android WatchFace サンプルアプリ
データの挿入
過去のデータを挿入するには、まず DataSet
インスタンスを作成します。
Kotlin
// Declare that the data being inserted was collected during the past hour. val endTime = LocalDateTime.now().atZone(ZoneId.systemDefault()) val startTime = endTime.minusHours(1) // Create a data source val dataSource = DataSource.Builder() .setAppPackageName(this) .setDataType(DataType.TYPE_STEP_COUNT_DELTA) .setStreamName("$TAG - step count") .setType(DataSource.TYPE_RAW) .build() // For each data point, specify a start time, end time, and the // data value -- in this case, 950 new steps. val stepCountDelta = 950 val dataPoint = DataPoint.builder(dataSource) .setField(Field.FIELD_STEPS, stepCountDelta) .setTimeInterval(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS) .build() val dataSet = DataSet.builder(dataSource) .add(dataPoint) .build()
Java
// Declare that the data being inserted was collected during the past hour. ZonedDateTime endTime = LocalDateTime.now().atZone(ZoneId.systemDefault()); ZonedDateTime startTime = endTime.minusHours(1); // Create a data source DataSource dataSource = new DataSource.Builder() .setAppPackageName(this) .setDataType(DataType.TYPE_STEP_COUNT_DELTA) .setStreamName("$TAG - step count") .setType(DataSource.TYPE_RAW) .build(); // For each data point, specify a start time, end time, and the // data value -- in this case, 950 new steps. int stepCountDelta = 950; DataPoint dataPoint = DataPoint.builder(dataSource) .setField(Field.FIELD_STEPS, stepCountDelta) .setTimeInterval(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS) .build(); DataSet dataSet = DataSet.builder(dataSource) .add(dataPoint) .build();
DataSet
インスタンスを作成したら、
HistoryClient.insertData
メソッドを使用すると、この履歴データを非同期で追加できます。
Kotlin
Fitness.getHistoryClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions)) .insertData(dataSet) .addOnSuccessListener { Log.i(TAG, "DataSet added successfully!") } .addOnFailureList>ener { e - Log.w(TAG, "There was an error adding the DataSet", e) }
Java
Fitness.getHistoryClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions)) .insertData(dataSet) .addOnSuccessListener (unused -> Log.i(TAG, "DataSet added successfully!")) .addOnFailureLi>stener(e - Log.w(TAG, "There was an error adding the DataSet", e)); }
競合するデータポイントを管理する
各
DataPoint
を DataSet
として、startTime
と endTime
その DataSet
内のユニーク間隔、DataPoint
の間に重複なし
説明します。
アプリが既存のバージョンと競合する新しい DataPoint
を挿入しようとした場合
DataPoint
インスタンスの場合、新しい DataPoint
は破棄されます。新しい
DataPoint
が既存のデータポイントと重複する可能性がある場合は、
HistoryClient.updateData
メソッド(データを更新するを参照)
図 1. insertData()
メソッドによる新しいデータポイントの処理方法
既存の DataPoint
と競合します。
データの更新
Google Fit では、健康とウェルネスに関する過去のデータをアプリで更新できます。
挿入しました。新しいDataSet
の過去のデータを追加したり、新しい
既存のデータと競合しない DataPoint
個のインスタンス
ポイントを確認するには、HistoryApi.insertData
メソッドを使用します。
過去のデータを更新するには、HistoryClient.updateData
メソッドを使用します。この
メソッドは、DataPoint
と重複する既存の DataPoint
インスタンスを削除します。
追加されているインスタンスの数を表します。
健康とウェルネスに関する過去のデータを更新するには、まず DataSet
を作成します
instance:
Kotlin
// Declare that the historical data was collected during the past 50 minutes. val endTime = LocalDateTime.now().atZone(ZoneId.systemDefault()) val startTime = endTime.minusMinutes(50) // Create a data source val dataSource = DataSource.Builder() .setAppPackageName(this) .setDataType(DataType.TYPE_STEP_COUNT_DELTA) .setStreamName("$TAG - step count") .setType(DataSource.TYPE_RAW) .build() // Create a data set // For each data point, specify a start time, end time, and the // data value -- in this case, 1000 new steps. val stepCountDelta = 1000 val dataPoint = DataPoint.builder(dataSource) .setTimeInterval(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS) .setField(Field.FIELD_STEPS, stepCountDelta) .build() val dataSet = DataSet.builder(dataSource) .add(dataPoint) .build()
Java
// Declare that the historical data was collected during the past 50 minutes. ZonedDateTime endTime = LocalDateTime.now().atZone(ZoneId.systemDefault()); ZonedDateTime startTime = endTime.minusMinutes(50); // Create a data source DataSource dataSource = new DataSource.Builder() .setAppPackageName(this) .setDataType(DataType.TYPE_STEP_COUNT_DELTA) .setStreamName("$TAG - step count") .setType(DataSource.TYPE_RAW) .build(); // Create a data set // For each data point, specify a start time, end time, and the // data value -- in this case, 1000 new steps. int stepCountDelta = 1000; DataPoint dataPoint = DataPoint.builder(dataSource) .setTimeInterval(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS) .setField(Field.FIELD_STEPS, stepCountDelta) .build(); DataSet dataSet = DataSet.builder(dataSource) .add(dataPoint) .build();
次に、DataUpdateRequest.Builder()
を使用して新しいデータ更新リクエストを作成します。
HistoryClient.updateData
メソッドを使用してリクエストを行います。
Kotlin
val request = DataUpdateRequest.Builder() .setDataSet(dataSet) .setTimeInterval(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS) .build() Fitness.getHistoryClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions)) .updateData(request) .addOnSuccessListener { Log.i(TAG, "DataSet updated successfully!") } .addOnFailureList>ener { e - Log.w(TAG, "There was an error updating the DataSet", e) }
Java
DataUpdateRequest request = new DataUpdateRequest.Builder() .setDataSet(dataSet) .setTimeInterval(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS) .build(); Fitness.getHistoryClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions)) .updateData(request) .addOnSuccessListener(unused -> Log.i(TAG, "DataSet updated successfully!")) .addOnFailureLi>stener(e - Log.w(TAG, "There was an error updating the DataSet", e));
データの削除
Google Fit では、健康とウェルネスに関する過去のデータをアプリから削除できます 挿入しました。
過去のデータを削除するには、
HistoryClient.deleteData
メソッド:
Kotlin
// Declare that this code deletes step count information that was collected // throughout the past day. val endTime = LocalDateTime.now().atZone(ZoneId.systemDefault()) val startTime = endTime.minusDays(1) // Create a delete request object, providing a data type and a time interval val request = DataDeleteRequest.Builder() .setTimeInterval(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS) .addDataType(DataType.TYPE_STEP_COUNT_DELTA) .build() // Invoke the History API with the HistoryClient object and delete request, and // then specify a callback that will check the result. Fitness.getHistoryClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions)) .deleteData(request) .addOnSuccessListener { Log.i(TAG, "Data deleted successfully!") } .addOnFailureList>ener { e - Log.w(TAG, "There was an error with the deletion request", e) }
Java
// Declare that this code deletes step count information that was collected // throughout the past day. ZonedDateTime endTime = LocalDateTime.now().atZone(ZoneId.systemDefault()); ZonedDateTime startTime = endTime.minusDays(1); // Create a delete request object, providing a data type and a time interval DataDeleteRequest request = new DataDeleteRequest.Builder() .setTimeInterval(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS) .addDataType(DataType.TYPE_STEP_COUNT_DELTA) .build(); // Invoke the History API with the HistoryClient object and delete request, and // then specify a callback that will check the result. Fitness.getHistoryClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions)) .deleteData(request) .addOnSuccessListener (unused -> Log.i(TAG, "Data deleted successfully!")) .addOnFailureLi>stener(e - Log.w(TAG, "There was an error with the deletion request", e));
アプリは、特定のセッションまたは
すべてのデータを削除できます。詳細は API リファレンスを
DataDeleteRequest
。
データ更新に登録する
登録することで、アプリで生のセンサーデータをリアルタイムで読み取ることができます。
SensorsClient
。
その他の種類が少なく、手動でカウントされるデータについては、
アプリは、これらの測定値が挿入されたときに更新を受信するよう登録できる
Google Fit データベースたとえば、身長、
ウェイトリフティングなどのワークアウト詳しくは、こちらのリスト
サポートされています。
最新情報を登録するには、次のコマンドを使用します。
HistoryClient.registerDataUpdateListener
。
次のコード スニペットを使用すると、ユーザーが新しいスペースを入力すると、アプリに通知が送信されます。 値を返します。
Kotlin
val intent = Intent(this, MyDataUpdateService::class.java) val pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) val request = DataUpdateListenerRegistrationRequest.Builder() .setDataType(DataType.TYPE_WEIGHT) .setPendingIntent(pendingIntent) .build() Fitness.getHistoryClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions)) .registerDataUpdateListener(request) .addOnSuccessListener { Log.i(TAG, "DataUpdateListener registered") }
Java
Intent intent = new Intent(this, MyDataUpdateService.class); PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) DataUpdateListenerRegistrationRequest request = new DataUpdateListenerRegistrationRequest.Builder() .setDataType(DataType.TYPE_WEIGHT) .setPendingIntent(pendingIntent) .build(); Fitness.getHistoryClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions)) .registerDataUpdateListener(request) .addOnSuccessListener(unused -> Log.i(TAG, "DataUpdateListener registered"));
IntentService
を使用して、更新の通知を受け取ることができます。
Kotlin
class MyDataUpdateService : IntentService("MyDataUpdateService") { override fun onHandleIntent(intent: Intent?) { val update = DataUpdateNotification.getDataUpdateNotification(intent) // Show the time interval over which the data points were collected. // To extract specific data values, in this case the user's weight, // use DataReadRequest. update?.apply { val start = getUpdateStartTime(TimeUnit.MILLISECONDS) val end = getUpdateEndTime(TimeUnit.MILLISECONDS) Log.i(TAG, "Data Update start: $start end: $end DataType: ${dataType.name}") } } }
Java
public class MyDataUpdateService extends IntentService { public MyDataUpdateService(String name) { super("MyDataUpdateService"); } @Override protected void onHandleIntent(@Nullable Intent intent) { if (intent != null) { DataUpdateNotification update = DataUpdateNotification.getDataUpdateNotification(intent); // Show the time interval over which the data points // were collected. // To extract specific data values, in this case the user's weight, // use DataReadRequest. if (update != null) { long start = update.getUpdateStartTime(TimeUnit.MILLISECONDS); long end = update.getUpdateEndTime(TimeUnit.MILLISECONDS); } Log.i(TAG, "Data Update start: $start end: $end DataType: ${dataType.name}"); } } }
IntentService
は AndroidManifest.xml
ファイルで宣言する必要があります。