Fetch daily steps and calorie using Google Fit API

IMPORTANT : For Updated and Simplified code to fetch calories and steps for a particular date check this Article
Google Fit
The Google Fit APIs for Android are part of Google Play services and are supported in Android 2.3 (API level 9) and higher. Guide to set up Google Play Services can be found here.
The Google Fit consists of following APIs.
The History API provides access to the fitness history and lets apps perform bulk operations, like inserting, deleting, and reading fitness data. Apps can also import batch data into Google Fit. So In this tutorial we will be using the History API to fetch calorie burned and steps covered by the account holder on a particular date.
Create Google API Client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
// Create the Google API Client GoogleApiClient mClient = new GoogleApiClient.Builder(this) .addApi(Fitness.HISTORY_API) .addApi(Fitness.CONFIG_API) .addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ)) .useDefaultAccount() .addConnectionCallbacks( new GoogleApiClient.ConnectionCallbacks() { @Override public void onConnected(Bundle bundle) { //Async To fetch steps new FetchStepsAsync().execute(); } @Override public void onConnectionSuspended(int i) { // If your connection to the sensor gets lost at some point, // you'll be able to determine the reason and react to it here. if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) { Log.i(TAG, "Connection lost. Cause: Network Lost."); } else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) { Log.i(TAG, "Connection lost. Reason: Service Disconnected"); } } } ).addOnConnectionFailedListener( new GoogleApiClient.OnConnectionFailedListener() { // Called whenever the API client fails to connect. @Override public void onConnectionFailed(ConnectionResult result) { Log.i(TAG, "Connection failed. Cause: " + result.toString()); if (!result.hasResolution()) { // Show the localized error dialog GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), RevoBaseActivity.this, 0).show(); return; } // The failure has a resolution. Resolve it. // Called typically when the app is not yet authorized, and an // authorization dialog is displayed to the user. if (!authInProgress) { try { Log.i(TAG, "Attempting to resolve failed connection"); authInProgress = true; result.startResolutionForResult(RevoBaseActivity.this, REQUEST_OAUTH); } catch (IntentSender.SendIntentException e) { Log.e(TAG, "Exception while starting resolution activity", e); } } } } ).build(); mClient.connect(); |
Fetch User Google Fit Data
When the Google API Client is successfully connected, we will fetch the user data from Google Fit.
1 2 3 4 5 6 |
//Async To fetch steps new FetchStepsAsync().execute(); |
The above mentioned AsyncTask will be executed to get the step count for today.
FetchStepsAsync
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
private class FetchStepsAsync extends AsyncTask<Object, Object, Long> { protected Long doInBackground(Object... params) { long total = 0; PendingResult<DailyTotalResult> result = Fitness.HistoryApi.readDailyTotal(mClient, DataType.TYPE_STEP_COUNT_DELTA); DailyTotalResult totalResult = result.await(30, TimeUnit.SECONDS); if (totalResult.getStatus().isSuccess()) { DataSet totalSet = totalResult.getTotal(); if (totalSet != null) { total = totalSet.isEmpty() ? 0 : totalSet.getDataPoints().get(0).getValue(Field.FIELD_STEPS).asInt(); } } else { Log.w(TAG, "There was a problem getting the step count."); } return total; } @Override protected void onPostExecute(Long aLong) { super.onPostExecute(aLong); //Total steps covered for that day Log.i(TAG, "Total steps: " + aLong); } } |
If you want to fetch the total calorie burned, use the below function FetchCalorieAsync in place of FetchStepsAsync
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
private class FetchCalorieAsync extends AsyncTask<Object, Object, Long> { protected Long doInBackground(Object... params) { long total = 0; PendingResult<DailyTotalResult> result = Fitness.HistoryApi.readDailyTotal(mClient, DataType. TYPE_CALORIES_EXPENDED); DailyTotalResult totalResult = result.await(30, TimeUnit.SECONDS); if (totalResult.getStatus().isSuccess()) { DataSet totalSet = totalResult.getTotal(); if (totalSet != null) { total = totalSet.isEmpty() ? 0 : totalSet.getDataPoints().get(0).getValue(Field.FIELD_CALORIES).asInt(); } } else { Log.w(TAG, "There was a problem getting the calories."); } return total; } @Override protected void onPostExecute(Long aLong) { super.onPostExecute(aLong); //Total calories burned for that day Log.i(TAG, "Total calories: " + aLong); } } |
This will give you the total calories burned including the Inactive Calories (Calories burned while being idle/sleeping etc). We may filter the calorie burned based on activities like walking or running. I will cover this topic in the next tutorial.
Please let me know of what you think about this blog post. Valuable suggestions and requests are always welcome. Help me improve this blog!
Follow GadgetSaint on Facebook / Twitter for updates.
Happy coding 🙂
Wanna start your blog or site in 5 mins? Check out Official WordPress recommended web hosting Bluehost.
Very good.It’s help me a lot to integrate Google fit
Good tutorial, but i have a problem! When I run the application, just when I push the button to obtain the calories, the app closes without any error, what is the problem?
Can you post your Log?
I have the same problem, the app is crashing when i open it, this is the log:
05-23 15:29:47.350 15291-15758/com.ivan.lucian.fitbuddy31 E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.ivan.lucian.fitbuddy31, PID: 15291
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.IllegalStateException: Value is not in int format
at com.google.android.gms.common.internal.zzac.zza(Unknown Source)
at com.google.android.gms.fitness.data.Value.asInt(Unknown Source)
at com.ivan.lucian.fitbuddy31.MainActivity$FetchCalorieAsync.doInBackground(MainActivity.java:380)
at com.ivan.lucian.fitbuddy31.MainActivity$FetchCalorieAsync.doInBackground(MainActivity.java:370)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
for what i understand this line is the problem:
: totalSet.getDataPoints().get(0).getValue(Field.FIELD_CALORIES).asInt();
**** from log (Caused by: java.lang.IllegalStateException: Value is not in int format)*****
@Lucian: You right, problems came from there. I fixed by changing to asFloat() and change the get calories burned AsynTask to:
private class FetchCalorieAsync extends AsyncTask {
protected Float doInBackground(Object… params) {
float total = 0;
PendingResult result = Fitness.HistoryApi.readDailyTotal(mGoogleClient, DataType.TYPE_CALORIES_EXPENDED);
DailyTotalResult totalResult = result.await(30, TimeUnit.SECONDS);
if (totalResult.getStatus().isSuccess()) {
DataSet totalSet = totalResult.getTotal();
if (totalSet != null) {
total = totalSet.isEmpty()
? 0
: totalSet.getDataPoints().get(0).getValue(Field.FIELD_CALORIES).asFloat();
}//1205.4213
} else {
Log.w(“GoogleFit”, “There was a problem getting the calories.”);
}
return total;
}
@Override
protected void onPostExecute(Float aLong) {
super.onPostExecute(aLong);
//Total calories burned for that day
Log.i(“GoogleFit”, “Total calories: ” + aLong);
}
}
Are all the Google Fit APIs available for free if I use them in android apps that I will monetize ? If not, where can I find the pricing info ?
I think its free and no issues monetizing the app.
Im currently facing a problem with the code similar to yours. There is a total mismatch between the actual data and the data this code loads up! I have opened Google Fit Web on my desktop and I have my android app running on my device. I have a service which reads todays step count and calories every minute. For example, the initial count is 50 steps. Then I walked for few minutes and then checked the log. There is no increment in the step count for about 30 minutes, it was still 50. Then I refreshed the google fit web page, which loaded up the new steps and it has shown 90 steps which is expected. After that refresh even my log data got new step count of 90!
1) So, it means Google fit store doesn’t frequently refresh/load data from all the devices of the person? Or if it loads up, how frequently?
2) Do you know if there is any way we refresh the Google fit store every time before reading History API data? (The thing which refreshing the google fit web page does)
I actually doubt it Google fit store loads up data from all the fitness devices of a person only when we open the app or if we open/refresh the web page!
Do you have any idea/suggestion regarding this?
Hi, i would like to know is the google recorder api needed in order to retrieve the historical data.
I tested on redMi phone and this phone does not have link to google fit, and the total number of counts that is retrieved is 0, hence i wander if any services is need first then we are able to retrieve the step count.
Hi, I am not getting the calories. I tried both the methods asInt() and asFloat, but not able to get calories. Please help me to get the calories.
i have a problem . In this , suggestion of readDailyTotal is not come in after HISTORY_API.