欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

适用于Android的Google Fit:History API

程序员文章站 2022-04-07 21:54:59
...

Google Fit是一个平台,使开发人员可以构建专注于用户适应性数据的应用程序。 Google提供的工具之一是适用于Android的Google Fit,可以在Google Play服务中打包获得。

上一教程中 ,我们探讨了如何使用Google Fit Recording API通过Google Play服务存储健身数据。 本教程通过探讨如何使用History API访问和更新Google Fit中存储的数据来扩展该主题。

使Google Fit强大的原因是健身数据是通过Google Cloud Services存储的,因此以后可以访问和分析。 虽然SensorsRecording 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>

运行应用程序时,用户界面应如下所示:

适用于Android的Google Fit:History API

要继续设置项目,请打开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