Google Fit是一个平台,使开发人员可以构建专注于用户适应性数据的应用程序。 Google提供的工具之一是适用于Android的Google Fit,可以在Google Play服务中打包获得。
在上一教程中 ,我们探讨了如何使用Google Fit Recording API通过Google Play服务存储健身数据。 本教程通过探讨如何使用History API访问和更新Google Fit中存储的数据来扩展该主题。
使Google Fit强大的原因是健身数据是通过Google Cloud Services存储的,因此以后可以访问和分析。 虽然Sensors和Recording API专注于从Android设备收集健身数据,但History API旨在使开发人员可以轻松访问该存储的数据。
本教程将引导您完成一个示例项目,该示例项目演示如何使用History API。 成品可以从GitHub下载。
1.项目设置
步骤1:设定开发人员控制台
要使用Google Fit,您需要创建OAuth 2.0客户端ID并通过Google Developer Console注册您的应用程序。 在有关Google Fit Sensors API的教程中,您可以在Google Developer Console中找到有关如何设置项目的详细说明。
步骤2:建立Android专案
在Google Developer Console中配置了用于身份验证的应用程序后,请使用您注册的包名称创建一个新的Android应用程序,该SDK的最低SDK为9, Activity
为空。
创建基本的Android应用程序后,打开build.gradle并将Google Play服务包含在依赖项节点下,然后同步您的应用程序。
compile 'com.google.android.gms:play-services-fitness:8.4.0'
现在,您应该可以在应用程序中包含必要的Google Play服务类。 在开始学习本教程的Java代码之前,请打开activity_main.xml并对其进行修改,以使其包含五个Button
项,我们将使用它们来演示History API的某些功能。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical">
<Button
android:id="@+id/btn_view_week"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="View this weeks steps" />
<Button
android:id="@+id/btn_view_today"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="View today's steps"/>
<Button
android:id="@+id/btn_add_steps"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add step data for today" />
<Button
android:id="@+id/btn_update_steps"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Update step data for yesterday" />
<Button
android:id="@+id/btn_delete_steps"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Delete step data for yesterday" />
</LinearLayout>
运行应用程序时,用户界面应如下所示:
要继续设置项目,请打开MainActivity.java并实现以下回调和必需的方法:
-
GoogleApiClient.ConnectionCallbacks
-
GoogleAPiClient.OnConnectionFailedListener
-
View.OnClickListener
您还需要为GoogleApiClient
添加成员变量和对Button
对象的一组引用,如下所示。
public class MainActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
View.OnClickListener {
private Button mButtonViewWeek;
private Button mButtonViewToday;
private Button mButtonAddSteps;
private Button mButtonUpdateSteps;
private Button mButtonDeleteSteps;
private GoogleApiClient mGoogleApiClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonViewWeek = (Button) findViewById(R.id.btn_view_week);
mButtonViewToday = (Button) findViewById(R.id.btn_view_today);
mButtonAddSteps = (Button) findViewById(R.id.btn_add_steps);
mButtonUpdateSteps = (Button) findViewById(R.id.btn_update_steps);
mButtonDeleteSteps = (Button) findViewById(R.id.btn_delete_steps);
mButtonViewWeek.setOnClickListener(this);
mButtonViewToday.setOnClickListener(this);
mButtonAddSteps.setOnClickListener(this);
mButtonUpdateSteps.setOnClickListener(this);
mButtonDeleteSteps.setOnClickListener(this);
}
@Override
public void onConnectionSuspended(int i) {
Log.e("HistoryAPI", "onConnectionSuspended");
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.e("HistoryAPI", "onConnectionFailed");
}
public void onConnected(@Nullable Bundle bundle) {
Log.e("HistoryAPI", "onConnected");
}
@Override
public void onClick(View v) {
}
}
设置示例项目所需要做的最后一件事就是连接到Google Play服务。 这可以在onCreate()
方法的末尾完成。
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addConnectionCallbacks(this)
.enableAutoManage(this, 0, this)
.build();
使用上述代码,我们将连接到Google Play服务,并请求访问Google Fit中的History API以及读取和写入活动数据的权限。 通过添加enableAutoManage
属性,Google Play服务可以正确管理连接和断开连接。
2.使用Google Fit History API
使用History API,您可以检索和汇总数据,插入在应用程序中收集的值或删除可能存储的数据。 需要注意的重要一件事是,本教程中的所有History API操作都必须在主线程之外完成。 换句话说,每个操作都在AsyncTask
:
private class ViewWeekStepCountTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
displayLastWeeksData();
return null;
}
}
步骤1:随着时间显示数据
您可能要执行的一项任务是使用或显示随时间推移收集的数据。 您可以通过为适合某些查询参数的特定类型的数据创建一个新的DataReadRequest
来做到这一点。
您可以按时间或会话将这些数据分组到Bucket
对象中。 在此示例中,您请求上周的汇总步骤数据,并按日期对这些数据进行存储。
Calendar cal = Calendar.getInstance();
Date now = new Date();
cal.setTime(now);
long endTime = cal.getTimeInMillis();
cal.add(Calendar.WEEK_OF_YEAR, -1);
long startTime = cal.getTimeInMillis();
java.text.DateFormat dateFormat = DateFormat.getDateInstance();
Log.e("History", "Range Start: " + dateFormat.format(startTime));
Log.e("History", "Range End: " + dateFormat.format(endTime));
//Check how many steps were walked and recorded in the last 7 days
DataReadRequest readRequest = new DataReadRequest.Builder()
.aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA)
.bucketByTime(1, TimeUnit.DAYS)
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
.build();
创建DataReadRequest
,您可以使用Fitness.HistoryApi.readData
命令从GoogleApiClient
请求数据。 您还可以在API客户端上调用await
,以便线程在等待查询时停滞多达一分钟。 如果出现问题,则该线程在该分钟后继续。
DataReadResult dataReadResult = Fitness.HistoryApi.readData(mGoogleApiClient, readRequest).await(1, TimeUnit.MINUTES);
如果呼叫成功返回,则可以从DataReadResult
对象访问用户的适应性数据。 您的步骤数据请求将在Bucket
对象中返回,尽管其他类型的数据也将作为DataSet
对象的List
返回。 根据返回的数据类型,可以使用以下代码访问它:
//Used for aggregated data
if (dataReadResult.getBuckets().size() > 0) {
Log.e("History", "Number of buckets: " + dataReadResult.getBuckets().size());
for (Bucket bucket : dataReadResult.getBuckets()) {
List<DataSet> dataSets = bucket.getDataSets();
for (DataSet dataSet : dataSets) {
showDataSet(dataSet);
}
}
}
//Used for non-aggregated data
else if (dataReadResult.getDataSets().size() > 0) {
Log.e("History", "Number of returned DataSets: " + dataReadResult.getDataSets().size());
for (DataSet dataSet : dataReadResult.getDataSets()) {
showDataSet(dataSet);
}
}
然后,您可以从返回的DataSet
对象中检索每个DataPoint
。
private void showDataSet(DataSet dataSet) {
Log.e("History", "Data returned for Data type: " + dataSet.getDataType().getName());
DateFormat dateFormat = DateFormat.getDateInstance();
DateFormat timeFormat = DateFormat.getTimeInstance();
for (DataPoint dp : dataSet.getDataPoints()) {
Log.e("History", "Data point:");
Log.e("History", "\tType: " + dp.getDataType().getName());
Log.e("History", "\tStart: " + dateFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)) + " " + timeFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)));
Log.e("History", "\tEnd: " + dateFormat.format(dp.getEndTime(TimeUnit.MILLISECONDS)) + " " + timeFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)));
for(Field field : dp.getDataType().getFields()) {
Log.e("History", "\tField: " + field.getName() +
" Value: " + dp.getValue(field));
}
}
}
如果用户设备上的应用在上周内已打开Recording API,则您会收到该应用每天处于活动状态的数据。 上面代码中的日志应类似于以下内容:
E/History: Range Start: Feb 17, 2016
E/History: Range End: Feb 24, 2016
E/History: Number of buckets: 7
E/History: Data returned for Data type: com.google.step_count.delta
E/History: Data point:
E/History: Type: com.google.step_count.delta
E/History: Start: Feb 17, 2016 11:01:46 PM
E/History: End: Feb 17, 2016 11:01:46 PM
E/History: Field: steps Value: 9360
E/History: Data returned for Data type: com.google.step_count.delta
E/History: Data returned for Data type: com.google.step_count.delta
E/History: Data returned for Data type: com.google.step_count.delta
E/History: Data point:
E/History: Type: com.google.step_count.delta
E/History: Start: Feb 21, 2016 9:58:03 AM
E/History: End: Feb 21, 2016 9:58:03 AM
E/History: Field: steps Value: 10041
E/History: Data returned for Data type: com.google.step_count.delta
E/History: Data point:
E/History: Type: com.google.step_count.delta
E/History: Start: Feb 21, 2016 11:22:53 PM
E/History: End: Feb 22, 2016 11:22:53 PM
E/History: Field: steps Value: 10786
E/History: Data returned for Data type: com.google.step_count.delta
E/History: Data point:
E/History: Type: com.google.step_count.delta
E/History: Start: Feb 22, 2016 11:06:31 PM
E/History: End: Feb 23, 2016 11:06:31 PM
E/History: Field: steps Value: 13099
E/History: Data returned for Data type: com.google.step_count.delta
E/History: Data point:
E/History: Type: com.google.step_count.delta
E/History: Start: Feb 23, 2016 11:02:31 PM
E/History: End: Feb 24, 2016 11:02:31 PM
E/History: Field: steps Value: 9765
步骤2:显示今天的数据
现在,您知道如何根据时间范围检索Google Fit数据。 开发人员常用的一种用例是需要当天的数据。 幸运的是,Google通过添加Fitness.HistoryApi.readDailyTotal
调用Fitness.HistoryApi.readDailyTotal
了此操作,该调用创建了DailyTotalResult
对象,其中包含当天收集的数据。
private void displayStepDataForToday() {
DailyTotalResult result = Fitness.HistoryApi.readDailyTotal( mGoogleApiClient, DataType.TYPE_STEP_COUNT_DELTA ).await(1, TimeUnit.MINUTES);
showDataSet(result.getTotal());
}
上面的代码注销了用户当天的步数数据。
E/History: Data returned for Data type: com.google.step_count.delta
E/History: Data point:
E/History: Type: com.google.step_count.delta
E/History: Start: Feb 24, 2016 8:39:59 AM
E/History: End: Feb 24, 2016 8:39:59 AM
E/History: Field: steps Value: 9474
步骤3:将资料插入Google Fit
能够从Google Fit读取数据很重要,但有时您可能需要将自己收集的数据添加到Google Fit数据存储中。 为此,您需要为数据选择一个时间范围,并创建一个DataSource
对象,该对象表示您放入Google Fit中的信息的种类。 接下来,创建一个DataSet
对象,并将新的DataPoint
放入其中以进行插入操作。
对于此示例,我们将假设用户走了100万步,或大约500英里,并将原始步数据插入用户活动的最后一小时。
重要的是要注意,如果您选择一个跨越多天的时间范围,则插入的步数将在这些天之间平均分配。
Calendar cal = Calendar.getInstance();
Date now = new Date();
cal.setTime(now);
long endTime = cal.getTimeInMillis();
cal.add(Calendar.HOUR_OF_DAY, -1);
long startTime = cal.getTimeInMillis();
DataSource dataSource = new DataSource.Builder()
.setAppPackageName(this)
.setDataType(DataType.TYPE_STEP_COUNT_DELTA)
.setName("Step Count")
.setType(DataSource.TYPE_RAW)
.build();
int stepCountDelta = 1000000;
DataSet dataSet = DataSet.create(dataSource);
DataPoint point = dataSet.createDataPoint()
.setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS);
point.getValue(Field.FIELD_STEPS).setInt(stepCountDelta);
dataSet.add(point);
创建DataSet
对象后,您可以使用History API的insertData
调用将其插入Google Fit数据存储insertData
。
Fitness.HistoryApi.insertData(mGoogleApiClient, dataSet).await(1, TimeUnit.MINUTES);
如果插入用户的步骤,然后阅读活动日志,则应该看到类似以下内容的内容:
E/History: Data returned for Data type: com.google.step_count.delta
E/History: Data point:
E/History: Type: com.google.step_count.delta
E/History: Start: Feb 27, 2016 10:05:18 PM
E/History: End: Feb 28, 2016 10:05:18 PM
E/History: Field: steps Value: 1008747
步骤4:在Google Fit上更新资料
将数据插入Google Fit后,如果该数据与现有数据重叠,则无法再插入该类型的数据。 如果用户先走了500英里然后又走了500英里,这可能会引起问题。
要解决此问题,您需要使用updateData
调用。 幸运的是,更新数据几乎与插入新数据相同,只不过您创建的是DataUpdateRequest
。
Calendar cal = Calendar.getInstance();
Date now = new Date();
cal.setTime(now);
long endTime = cal.getTimeInMillis();
cal.add(Calendar.HOUR_OF_DAY, -1);
long startTime = cal.getTimeInMillis();
DataSource dataSource = new DataSource.Builder()
.setAppPackageName(this)
.setDataType(DataType.TYPE_STEP_COUNT_DELTA)
.setName("Step Count")
.setType(DataSource.TYPE_RAW)
.build();
int stepCountDelta = 2000000;
DataSet dataSet = DataSet.create(dataSource);
DataPoint point = dataSet.createDataPoint()
.setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS);
point.getValue(Field.FIELD_STEPS).setInt(stepCountDelta);
dataSet.add(point);
DataUpdateRequest updateRequest = new DataUpdateRequest.Builder().setDataSet(dataSet).setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS).build();
Fitness.HistoryApi.updateData(mGoogleApiClient, updateRequest).await(1, TimeUnit.MINUTES);
如果要在执行上述操作后第二天注销用户的步骤,则应该看到超过200万个步骤。
E/History: Data returned for Data type: com.google.step_count.delta
E/History: Data point:
E/History: Type: com.google.step_count.delta
E/History: Start: Feb 27, 2016 10:05:18 PM
E/History: End: Feb 28, 2016 10:05:18 PM
E/History: Field: steps Value: 2008747
第5步:从Google Fit中删除数据
通过Google Fit History API可以执行的最终操作是删除存储在Google Fit中的数据的功能。 这可以通过选择日期范围,创建DataDeleteRequest
对象并从History API调用deleteData
来完成。 虽然您可以删除自己插入的数据,但不会删除Google Fit存储的数据。
Calendar cal = Calendar.getInstance();
Date now = new Date();
cal.setTime(now);
long endTime = cal.getTimeInMillis();
cal.add(Calendar.DAY_OF_YEAR, -1);
long startTime = cal.getTimeInMillis();
DataDeleteRequest request = new DataDeleteRequest.Builder()
.setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
.addDataType(DataType.TYPE_STEP_COUNT_DELTA)
.build();
Fitness.HistoryApi.deleteData(mGoogleApiClient, request).await(1, TimeUnit.MINUTES);
结论
如您所见,History API是用于访问和操纵Google Fit数据存储的功能强大的工具。 虽然其他Google Fit API旨在收集数据,但History API允许您维护和访问数据以进行分析。 现在,您应该能够使用该功能创建出色的应用程序。
翻译自: https://code.tutsplus.com/tutorials/google-fit-for-android-history-api--cms-25856