Work with historical data

The History API lets your app perform bulk operations on the fitness store: reading, inserting, updating, and deleting historical health and wellness data. Use the History API to do the following:

  • Read health and wellness data that was inserted or recorded using other apps.
  • Import batch data into Google Fit.
  • Update data in Google Fit.
  • Delete historical data that your app previously stored.

To insert data that contains session metadata, use the Sessions API .

Read data

The following sections cover how to read different kinds of aggregate data.

Read detailed and aggregate data

To read historical data, create a DataReadRequest instance.

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

The previous example uses aggregated data points, where each DataPoint represents the number of steps walked in a day. For this particular use case, aggregated data points have two advantages:

  • Your app and the fitness store exchange smaller amounts of data.
  • Your app doesn't have to aggregate the data manually.

Aggregate data for multiple activity types

Your app can use data requests to retrieve many different types of data. The following example shows how to create a DataReadRequest to get calories burned for each activity performed within the specified time range. The resulting data matches the calories per activity as reported in the Google Fit app, where each activity gets its own bucket of calorie data.

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

After you create a DataReadRequest instance, use the HistoryClient.readData() method to asynchronously read historical data.

The following example demonstrates how to obtain the DataPoint instances from a 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 
 (); 
 } 

Read daily total data

Google Fit also provides simple access to the daily total of a specified data type. Use the HistoryClient.readDailyTotal() method to retrieve the data type that you specify as of midnight of the current day in the device's current timezone. For example, pass in the TYPE_STEP_COUNT_DELTA data type to this method to retrieve the daily total steps. You can pass in an instantaneous data type that has an aggregate daily total. For more information on the supported data types, see DataType.getAggregateType .

Google Fit doesn't require authorization to subscribe to TYPE_STEP_COUNT_DELTA updates from the HistoryClient.readDailyTotal() method when this method is called using the default account and no scopes are specified. This can be useful if you require step data for use in areas where you're unable to show the permissions panel, for example on Wear OS watch faces.

Users prefer to see consistent step counts across the Google Fit app, other apps, and Wear OS watch faces, because this provides them with a consistent and reliable experience. To keep step counts consistent, subscribe to steps in the Google Fit platform from your app or watch face, and then update the count in onExitAmbient() . For more information on how to use this data in a watch face, see Watch face complications and the Android WatchFace sample application .

Insert data

To insert historical data, first create a DataSet instance:

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

After you create a DataSet instance, use the HistoryClient.insertData method to asynchronously add this historical data.

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 
 )); 
 } 

Manage conflicting data points

Each DataPoint in your app's DataSet must have a startTime and an endTime that defines a unique interval within that DataSet , with no overlap between DataPoint instances.

If your app attempts to insert a new DataPoint that conflicts with an existing DataPoint instance, the new DataPoint is discarded. To insert a new DataPoint that might overlap with existing data points, use the HistoryClient.updateData method described in Update data .

A data point can't be inserted if its duration overlaps with any existing data
points

Figure 1.How the insertData() method handles new data points that conflict with an existing DataPoint .

Update data

Google Fit lets your app update historical health and wellness data it previously inserted. To add historical data for a new DataSet , or to add new DataPoint instances that don't conflict with existing data points , use the HistoryApi.insertData method.

To update historical data, use the HistoryClient.updateData method. This method deletes any existing DataPoint instances that overlap with DataPoint instances added using this method.

To update historical health and wellness data, first create a 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 
 (); 

Then, use DataUpdateRequest.Builder() to create a new data update request, and use the HistoryClient.updateData method to make the request:

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

Delete data

Google Fit lets your app delete historical health and wellness data it previously inserted.

To delete historical data, use the HistoryClient.deleteData method:

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

Apps can delete data from specific sessions or delete all data. For more information, see the API reference for DataDeleteRequest .

Register for data updates

Your app can read raw sensor data in real time by registering with SensorsClient .

For other types of data that are less frequent and are manually counted, your app can register to receive updates when these measurements are inserted into the Google Fit database. Examples of these data types include height, weight, and workouts like weight lifting; for more details, see the full list of supported data types . To register for updates, use HistoryClient.registerDataUpdateListener .

The following code snippet lets an app be notified when the user enters a new value for their weight:

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" 
 )); 

An IntentService can be used to receive notifications of updates:

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}" 
 ); 
  
 } 
  
 } 
 } 

The IntentService must be declared in your AndroidManifest.xml file.

Create a Mobile Website
View Site in Mobile | Classic
Share by: