Google Fit — это платформа, которая позволяет разработчикам создавать приложения, ориентированные на данные о пригодности пользователей. Одним из инструментов, предоставляемых Google, является Google Fit для Android, который доступен в виде пакета в Сервисах Google Play.
В предыдущем уроке мы изучали, как использовать Google Fit Recording API для хранения данных о фитнесе через Сервисы Google Play. В этом учебном пособии эта тема раскрывается путем изучения того, как получать доступ к данным, хранящимся в Google Fit, и обновлять их с помощью API History.
Что делает Google Fit мощным, так это то, что данные о фитнесе хранятся через облачные сервисы Google, что позволяет получать к ним доступ и анализировать их позднее. В то время как API датчиков и записи ориентированы на сбор данных о пригодности с устройства Android, API истории предназначен для того, чтобы предоставить разработчикам легкий доступ к этим сохраненным данным.
В этом руководстве вы познакомитесь с примером проекта, который демонстрирует, как работать с History API. Готовый продукт можно скачать с GitHub .
1. Настройка проекта
Шаг 1. Настройка консоли разработчика
Чтобы использовать Google Fit, вам нужно создать идентификатор клиента OAuth 2.0 и зарегистрировать свое приложение через Консоль разработчика Google. Подробное объяснение того, как настроить проект в консоли разработчика Google, можно найти в моем руководстве по API Google Fit Sensors .
Шаг 2. Создайте проект Android
Как только ваше приложение будет настроено для аутентификации в консоли разработчика Google, используйте имя пакета, которое вы зарегистрировали, чтобы создать новое приложение Android с минимальным SDK 9 и пустым Activity .
После создания базового приложения для Android откройте build.gradle , включите Google Play Services в узле зависимостей и синхронизируйте свое приложение.
|
1
|
compile ‘com.google.android.gms:play-services-fitness:8.4.0’
|
Теперь вы сможете включать необходимые классы Google Play Services в свое приложение. Прежде чем мы углубимся в код Java для этого учебника, откройте файл activity_main.xml и изменим его так, чтобы он включал пять элементов Button , которые мы будем использовать для демонстрации некоторых функций API истории.
|
01
02
03
04
05
06
07
08
09
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
|
<?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 , как показано ниже.
|
01
02
03
04
05
06
07
08
09
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
|
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() .
|
1
2
3
4
5
6
|
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 и запрашиваем доступ к History API в Google Fit, а также разрешение на чтение и запись данных об активности. Добавляя свойство enableAutoManage , Службы Google Play управляют подключением и отключением правильно.
2. Использование API Google Fit History
Используя History API, вы можете извлекать и объединять данные, вставлять значения, которые вы собрали в своем приложении, или удалять данные, которые могут быть сохранены. Важно отметить, что все операции по History API в этом руководстве должны выполняться вне основного потока. Другими словами, каждая операция выполняется в AsyncTask :
|
1
2
3
4
5
6
|
private class ViewWeekStepCountTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void… params) {
displayLastWeeksData();
return null;
}
}
|
Шаг 1: Отображение данных с течением времени
Одна из задач, которую вы, возможно, захотите выполнить, — использовать или отображать данные, которые были собраны с течением времени. Вы можете сделать это, создав новый DataReadRequest для определенного типа данных, который соответствует некоторым параметрам запроса.
Вы можете сгруппировать эти данные вместе в объектах Bucket по времени или сеансам. В этом примере вы запрашиваете агрегированные данные шага за последнюю неделю и собираете эти данные по дням.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
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();
|
GoogleApiClient DataReadRequest , вы можете запросить данные у GoogleApiClient с помощью команды Fitness.HistoryApi.readData . Вы также вызываете await на API-клиенте, так что поток ожидает до минуты, ожидая запроса. Если что-то идет не так, поток продолжается после этой минуты.
|
1
|
DataReadResult dataReadResult = Fitness.HistoryApi.readData(mGoogleApiClient, readRequest).await(1, TimeUnit.MINUTES);
|
Если вызов успешно завершен, вы можете получить доступ к данным о пригодности пользователя из объекта DataReadResult . Ваш запрос данных шага возвращается в объектах Bucket , хотя другие типы данных возвращаются в виде List объектов DataSet . В зависимости от типа возвращаемых данных вы можете получить к ним следующий код:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
//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);
}
}
|
Затем вы можете извлечь каждый DataPoint из объектов DataSet , которые были возвращены.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
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));
}
}
}
|
Если приложение на устройстве пользователя включило API записи в течение последней недели, вы получите данные за каждый день, когда оно было активным. Журналы из приведенного выше кода должны выглядеть примерно так:
|
01
02
03
04
05
06
07
08
09
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
|
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 , который создает объект DailyTotalResult содержащий данные, собранные за день.
|
1
2
3
4
|
private void displayStepDataForToday() {
DailyTotalResult result = Fitness.HistoryApi.readDailyTotal( mGoogleApiClient, DataType.TYPE_STEP_COUNT_DELTA ).await(1, TimeUnit.MINUTES);
showDataSet(result.getTotal());
}
|
Приведенный выше код записывает данные о шагах пользователя за день.
|
1
2
3
4
5
6
|
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 для операции вставки.
В этом примере мы предположим, что пользователь прошел один миллион шагов, или примерно 500 миль, и вставим эти необработанные данные о шагах в последний час активности пользователя.
Важно отметить, что если вы выберете временной диапазон, охватывающий несколько дней, количество вставляемых шагов будет равномерно распределено между этими днями.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
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 его можно вставить в хранилище данных Google Fit с помощью вызова insertData API insertData .
|
1
|
Fitness.HistoryApi.insertData(mGoogleApiClient, dataSet).await(1, TimeUnit.MINUTES);
|
Если вы вставите шаги пользователя, а затем прочитаете журнал активности, вы должны увидеть что-то похожее на следующее:
|
1
2
3
4
5
6
|
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 .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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);
|
Если вы должны были выйти из системы на следующий день после выполнения вышеизложенного, вы должны увидеть более двух миллионов шагов.
|
1
2
3
4
5
6
|
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
Последней операцией, доступной через API истории Google Fit, является возможность удаления данных, которые вы сохранили в Google Fit. Это можно сделать, выбрав диапазон дат, создав объект DataDeleteRequest и вызвав deleteData из History API. Хотя вы можете удалить свои собственные вставленные данные, данные, сохраненные в Google Fit, не удаляются.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
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 и управления им. В то время как другие API Google Fit предназначены для сбора данных, API истории позволяет поддерживать и получать доступ к данным для анализа. Теперь вы сможете создавать удивительные приложения, использующие эту функцию.