L'API History permet à votre application d'effectuer des opérations groupées sur la boutique de remise en forme: la lecture, l'insertion, la mise à jour et la suppression des données historiques de santé et de bien-être. Utilisez l'API History pour effectuer les opérations suivantes :
- Lire les données de santé et de bien-être qui ont été insérées ou enregistrées à l'aide d'autres applications.
- Importez des données par lot dans Google Fit.
- Mettre à jour les données dans Google Fit.
- Supprimez les données historiques précédemment stockées par votre appli.
Pour insérer des données contenant des métadonnées de session, utilisez la méthode API Sessions :
Lire des données
Les sections suivantes expliquent comment lire différents types de données globales.
Lire des données détaillées et agrégées
Pour lire les données historiques, créez un
DataReadRequest
Compute Engine.
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 bucketBySession allows // bucketing by <a href="/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();
L'exemple précédent utilise des points de données agrégés, où chaque DataPoint
représente le nombre de pas effectués par jour. Pour ce cas d'utilisation particulier,
les points de données agrégées
présentent deux avantages:
- Votre application et la boutique de remise en forme échangent de plus petites quantités de données.
- Votre application n'a pas besoin d'agréger les données manuellement.
Données globales pour plusieurs types d'activités
Votre application peut utiliser des demandes de données pour récupérer de nombreux types de données différents. La
l'exemple suivant montre comment créer
DataReadRequest
pour connaître les calories brûlées dans chaque activité effectuée au cours de la
période spécifiée. Les données obtenues correspondent aux calories par activité, comme indiqué dans l'application Google Fit, où chaque activité dispose de son propre ensemble de données sur les calories.
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();
Après avoir créé une instance DataReadRequest
, utilisez la méthode HistoryClient.readData()
pour lire de manière asynchrone les données historiques.
L'exemple suivant montre comment obtenir les instances DataPoint
à partir d'un 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(); }
Lire les données totales quotidiennes
Google Fit permet également d'accéder facilement au total quotidien d'un type de données spécifié. Utilisez la méthode HistoryClient.readDailyTotal()
pour récupérer le type de données que vous spécifiez à minuit du jour en cours dans le fuseau horaire actuel de l'appareil. Par exemple, transmettez le type de données TYPE_STEP_COUNT_DELTA
à cette méthode pour récupérer le nombre total de pas quotidiens. Vous pouvez transmettre un type de données instantané ayant un rapport quotidien agrégé
total. Pour en savoir plus sur les types de données acceptés, consultez
DataType.getAggregateType
Google Fit n'a pas besoin d'autorisation pour s'abonner aux mises à jour TYPE_STEP_COUNT_DELTA
à partir de la méthode HistoryClient.readDailyTotal()
lorsque cette méthode est appelée à l'aide du compte par défaut et qu'aucun champ d'application n'est spécifié.
Cela peut être utile si vous avez besoin de données de pas dans des zones où vous ne pouvez pas afficher le panneau des autorisations, par exemple sur les cadrans Wear OS.
Les utilisateurs préfèrent voir un nombre de pas cohérent
dans l'application Google Fit,
d'autres applications et des cadrans Wear OS,
une expérience cohérente et fiable. Pour que le nombre de pas soit cohérent, abonnez-vous aux pas sur la plate-forme Google Fit depuis votre application ou votre cadran, puis mettez à jour le nombre dans onExitAmbient()
.
Pour en savoir plus sur l'utilisation de ces données dans un cadran, consultez
Complications des cadrans
et l'exemple d'application Android WatchFace.
Insérer des données
Pour insérer des données historiques, créez d'abord une instance 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();
Après avoir créé une instance DataSet
, utilisez la méthode
HistoryClient.insertData
pour ajouter ces données historiques de manière asynchrone.
Kotlin
Fitness.getHistoryClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions)) .insertData(dataSet) .addOnSuccessListener { Log.i(TAG, "DataSet added successfully!") } .addOnFailureListener { 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!")) .addOnFailureListener(e -> Log.w(TAG, "There was an error adding the DataSet", e)); }
Gérer les points de données en conflit
Chaque DataPoint
dans le DataSet
de votre application doit disposer d'un startTime
et d'un endTime
qui définissent un intervalle unique dans ce DataSet
, sans chevauchement entre les instances DataPoint
.
Si votre application tente d'insérer un nouvel élément DataPoint
en conflit avec une instance DataPoint
existante, le nouvel élément DataPoint
est supprimé. Pour insérer un nouveau
DataPoint
susceptibles de chevaucher des points de données existants, utilisez l'
HistoryClient.updateData
décrite dans la section Mettre à jour les données.
Figure 1. Comment la méthode insertData()
gère les nouveaux points de données en conflit avec un DataPoint
existant.
Mettre à jour des données
Google Fit permet à votre application de mettre à jour l'historique des données de santé et de bien-être qu'elle a précédemment insérées. Pour ajouter des données historiques pour un nouvel élément DataSet
ou pour ajouter des instances DataPoint
qui ne entrent pas en conflit avec les points de données existants, utilisez la méthode HistoryApi.insertData
.
Pour mettre à jour les données historiques, utilisez la méthode HistoryClient.updateData
. Ce
supprime toutes les instances DataPoint
existantes qui chevauchent DataPoint
.
que vous pouvez ajouter à l'aide de cette méthode.
Pour mettre à jour l'historique des données de santé et de bien-être, créez d'abord un 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();
Ensuite, utilisez DataUpdateRequest.Builder()
pour créer une requête de mise à jour des données.
Utilisez la méthode HistoryClient.updateData
pour effectuer la requête:
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!") } .addOnFailureListener { 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!")) .addOnFailureListener(e -> Log.w(TAG, "There was an error updating the DataSet", e));
Supprimer des données
Google Fit permet à votre application de supprimer l'historique des données de santé et de bien-être qu'elle a précédemment insérées.
Pour supprimer des données historiques, utilisez le
HistoryClient.deleteData
méthode:
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!") } .addOnFailureListener { 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!")) .addOnFailureListener(e -> Log.w(TAG, "There was an error with the deletion request", e));
Les applications peuvent supprimer les données de sessions spécifiques ou toutes les données. Pour en savoir plus, consultez la documentation de référence de l'API
DataDeleteRequest
S'inscrire pour recevoir des informations sur les données
Votre application peut lire les données brutes des capteurs en temps réel en s'enregistrant via
SensorsClient
Pour les autres types de données moins fréquentes et comptabilisées manuellement, votre
l'application peut s'inscrire pour recevoir des mises à jour lorsque ces mesures sont insérées dans
la base de données Google Fit. Ces types de données
incluent la hauteur,
le poids et les exercices
comme l’haltérophilie ; Pour en savoir plus, consultez la liste complète
de types de données compatibles.
Pour vous inscrire aux mises à jour, utilisez HistoryClient.registerDataUpdateListener
.
L'extrait de code suivant permet à une application d'être avertie lorsque l'utilisateur saisit une nouvelle valeur pour son poids :
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"));
Un IntentService
peut être utilisé pour recevoir des notifications de mises à jour:
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}"); } } }
Le IntentService
doit être déclaré dans votre fichier AndroidManifest.xml
.