Advertisement
  1. Code
  2. Android SDK

Google Fit cho Android: History API

Scroll to top
This post is part of a series called Google Fit for Android.
Google Fit for Android: Recording API
Google Fit for Android: Sessions API

Vietnamese (Tiếng Việt) translation by Dai Phong (you can also view the original English article)

Google Fit là một nền tảng cho phép các nhà phát triển xây dựng các ứng dụng tập trung vào dữ liệu sức khoẻ của người dùng. Một trong những công cụ mà Google đã cung cấp là Google Fit cho Android, nó tồn tại như là một gói nằm trong Google Play Services.

Trong hướng dẫn trước, chúng ta đã khám phá cách làm thế nào để sử dụng Recording API của Google Fit để lưu trữ dữ liệu sức khoẻ thông qua Google Play Services. Hướng dẫn này sẽ tiếp tục khám phá cách để truy cập và cập nhật dữ liệu được lưu trữ trong Google Fit sử dụng History API.

Những gì làm cho Google Fit mạnh mẽ là dữ liệu sức khoẻ được lưu trữ thông qua Google Cloud Services, cái mà cho phép nó được truy cập và phân tích tại một thời điểm sau đó. Trong khi Sensors APIRecording API tập trung vào việc thu thập dữ liệu sức khoẻ từ một thiết bị Android, thì History API là nhằm giúp cho các nhà phát triển dễ dàng truy cập vào dữ liệu được lưu trữ.

Bài này sẽ hướng dẫn bạn tìm hiểu một dự án mẫu minh hoạ cách làm việc với History API. Sản phẩm cuối cùng có thể được tải về từ GitHub.

1. Thiết lập dự án

Bước 1: Thiết lập Developer Console

Để sử dụng Google Fit, bạn cần phải tạo ra một client ID OAuth 2.0 và đăng ký ứng dụng của bạn thông qua Google Developer Console. Bạn có thể tìm thấy một bài giải thích chi tiết về cách thiết lập một dự án trong Google Developer Console trong hướng dẫn của tôi về Sensors API của Google Fit.

Bước 2: Tạo dự án Android

Một khi ứng dụng của bạn đã được cấu hình để xác thực trong Google Developer Console, thì sử dụng tên gói mà bạn đăng ký để tạo một ứng dụng Android mới với SDK tối thiểu là 9 và một Activity rỗng.

Với ứng dụng Android cơ bản đã được tạo ra, mở build.gradle và bao gồm Google Play Services ở dưới phần dependencies và đồng bộ ứng dụng của bạn.

1
compile 'com.google.android.gms:play-services-fitness:8.4.0'

Bây giờ bạn có thể bao gồm các lớp cần thiết của Google Play Services vào ứng dụng của bạn. Trước khi chúng ta đi sâu vào trong code Java cho hướng dẫn này, hãy mở activity_main.xml và sửa đổi nó để nó bao gồm năm phần tử Button mà chúng ta sẽ sử dụng để minh hoạt một số chức năng của History API.

1
<?xml version="1.0" encoding="utf-8"?>
2
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
3
    android:layout_width="match_parent"
4
    android:layout_height="match_parent"
5
    android:paddingBottom="@dimen/activity_vertical_margin"
6
    android:paddingLeft="@dimen/activity_horizontal_margin"
7
    android:paddingRight="@dimen/activity_horizontal_margin"
8
    android:paddingTop="@dimen/activity_vertical_margin"
9
    android:orientation="vertical">
10
11
    <Button
12
        android:id="@+id/btn_view_week"
13
        android:layout_width="match_parent"
14
        android:layout_height="wrap_content"
15
        android:text="View this weeks steps" />
16
17
    <Button
18
        android:id="@+id/btn_view_today"
19
        android:layout_width="match_parent"
20
        android:layout_height="wrap_content"
21
        android:text="View today's steps"/>
22
23
    <Button
24
        android:id="@+id/btn_add_steps"
25
        android:layout_width="match_parent"
26
        android:layout_height="wrap_content"
27
        android:text="Add step data for today" />
28
29
    <Button
30
        android:id="@+id/btn_update_steps"
31
        android:layout_width="match_parent"
32
        android:layout_height="wrap_content"
33
        android:text="Update step data for yesterday" />
34
35
    <Button
36
        android:id="@+id/btn_delete_steps"
37
        android:layout_width="match_parent"
38
        android:layout_height="wrap_content"
39
        android:text="Delete step data for yesterday" />
40
41
</LinearLayout>

Khi bạn chạy ứng dụng của bạn, giao diện người dùng sẽ trông giống như thế này:

Để tiếp tục thiết lập dự án, hãy mở MainActivity.java của bạn và cài đặt các hàm callback và các phương thức cần thiết sau đây:

  • GoogleApiClient.ConnectionCallbacks
  • GoogleAPiClient.OnConnectionFailedListener
  • View.OnClickListener

Bạn cũng cần phải thêm một biến thành viên cho GoogleApiClient và một tập hợp các tham chiếu đến các đối tượng Button của bạn, như hình dưới đây.

1
public class MainActivity extends AppCompatActivity implements
2
    GoogleApiClient.ConnectionCallbacks,
3
    GoogleApiClient.OnConnectionFailedListener,
4
    View.OnClickListener {
5
 
6
    private Button mButtonViewWeek;
7
    private Button mButtonViewToday;
8
    private Button mButtonAddSteps;
9
    private Button mButtonUpdateSteps;
10
    private Button mButtonDeleteSteps;
11
12
    private GoogleApiClient mGoogleApiClient;
13
 
14
    @Override
15
    protected void onCreate(Bundle savedInstanceState) {
16
        super.onCreate(savedInstanceState);
17
        setContentView(R.layout.activity_main);
18
        
19
        mButtonViewWeek = (Button) findViewById(R.id.btn_view_week);
20
        mButtonViewToday = (Button) findViewById(R.id.btn_view_today);
21
        mButtonAddSteps = (Button) findViewById(R.id.btn_add_steps);
22
        mButtonUpdateSteps = (Button) findViewById(R.id.btn_update_steps);
23
        mButtonDeleteSteps = (Button) findViewById(R.id.btn_delete_steps);
24
25
        mButtonViewWeek.setOnClickListener(this);
26
        mButtonViewToday.setOnClickListener(this);
27
        mButtonAddSteps.setOnClickListener(this);
28
        mButtonUpdateSteps.setOnClickListener(this);
29
        mButtonDeleteSteps.setOnClickListener(this);
30
    }
31
 
32
    @Override
33
    public void onConnectionSuspended(int i) {
34
        Log.e("HistoryAPI", "onConnectionSuspended");
35
    }
36
37
    @Override
38
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
39
        Log.e("HistoryAPI", "onConnectionFailed");
40
    }
41
 
42
    public void onConnected(@Nullable Bundle bundle) {
43
        Log.e("HistoryAPI", "onConnected");
44
    }
45
46
 
47
    @Override
48
    public void onClick(View v) {
49
    }
50
}

Điều cuối cùng bạn cần làm để thiết lập dự án mẫu của bạn là kết nối với Google Play Services. Điều này có thể được thực hiện ở cuối của phương thức onCreate().

1
mGoogleApiClient = new GoogleApiClient.Builder(this)
2
        .addApi(Fitness.HISTORY_API)
3
        .addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
4
        .addConnectionCallbacks(this)
5
        .enableAutoManage(this, 0, this)
6
        .build();

Với đoạn code ở trên, chúng ta kết nối đến Google Play Services và yêu cầu truy cập vào History API trong Google Fit, cũng như quyền đọc và ghi dữ liệu hoạt động. Bằng cách thêm vào thuộc tính enableAutoManage, Google Play Services quản lý kết nối và ngắt kết nối một cách hợp lý.

2. Sử dụng History API của Google Fit

Sử dụng History API, bạn có thể truy xuất và tổng hợp dữ liệu, chèn các giá trị bạn đã tổng hợp trong ứng dụng của bạn hoặc xóa dữ liệu có thể đã được lưu trữ. Một điều quan trọng cần lưu ý là tất cả hoạt động của History API trong hướng dẫn này phải được thực hiện bên ngoài tiến trình chính. Nói cách khác, mỗi hoạt động diễn ra trong một AsyncTask:

1
private class ViewWeekStepCountTask extends AsyncTask<Void, Void, Void> {
2
    protected Void doInBackground(Void... params) {
3
        displayLastWeeksData();
4
        return null;
5
    }
6
}

Bước 1: Hiển thị dữ liệu theo thời gian

Một tác vụ mà bạn có thể muốn làm là sử dụng hoặc hiển thị dữ liệu đã được thu thập theo thời gian. Bạn có thể làm điều này bằng cách tạo ra một DataReadRequest mới cho một kiểu dữ liệu cụ thể phù hợp với một số tham số truy vấn.

Bạn có thể nhóm dữ liệu này lại với nhau trong các đối tượng Bucket theo thời gian hoặc các phiên. Đối với ví dụ này, bạn yêu cầu dữ liệu số bước đi được tổng hợp trong tuần và nhóm dữ liệu đó theo ngày.

1
Calendar cal = Calendar.getInstance();
2
Date now = new Date();
3
cal.setTime(now);
4
long endTime = cal.getTimeInMillis();
5
cal.add(Calendar.WEEK_OF_YEAR, -1);
6
long startTime = cal.getTimeInMillis();
7
8
java.text.DateFormat dateFormat = DateFormat.getDateInstance();
9
Log.e("History", "Range Start: " + dateFormat.format(startTime));
10
Log.e("History", "Range End: " + dateFormat.format(endTime));
11
12
//Check how many steps were walked and recorded in the last 7 days

13
DataReadRequest readRequest = new DataReadRequest.Builder()
14
        .aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA)
15
        .bucketByTime(1, TimeUnit.DAYS)
16
        .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
17
        .build();

Một khi bạn đã tạo DataReadRequest của bạn, bạn có thể yêu cầu dữ liệu từ GoogleApiClient bằng cách sử dụng câu lệnh Fitness.HistoryApi.readData. Bạn đồng thời gọi await trên client API để tiến trình ngưng chạy trong một phút trong khi chờ đợi truy vấn. Nếu có điều gì sai sót, tiến trình tiếp tục sau phút đó.

1
DataReadResult dataReadResult = Fitness.HistoryApi.readData(mGoogleApiClient, readRequest).await(1, TimeUnit.MINUTES);

Nếu trả về thành công, bạn có thể truy cập dữ liệu sức khoẻ của người dùng từ đối tượng DataReadResult. Yêu cầu dữ liệu bước đi của bạn sẽ được trả về trong các đối tượng Bucket, mặc dù các loại dữ liệu khác được trả về như một List các đối tượng DataSet. Tùy thuộc vào kiểu dữ liệu trả về, bạn có thể truy cập nó bằng đoạn code sau:

1
//Used for aggregated data

2
if (dataReadResult.getBuckets().size() > 0) {
3
    Log.e("History", "Number of buckets: " + dataReadResult.getBuckets().size());
4
    for (Bucket bucket : dataReadResult.getBuckets()) {
5
        List<DataSet> dataSets = bucket.getDataSets();
6
        for (DataSet dataSet : dataSets) {
7
            showDataSet(dataSet);
8
        }
9
    }
10
}
11
//Used for non-aggregated data

12
else if (dataReadResult.getDataSets().size() > 0) {
13
    Log.e("History", "Number of returned DataSets: " + dataReadResult.getDataSets().size());
14
    for (DataSet dataSet : dataReadResult.getDataSets()) {
15
        showDataSet(dataSet);
16
    }
17
}

Sau đó bạn có thể lấy mỗi Datapoint từ các đối tượng DataSet đã được trả về.

1
private void showDataSet(DataSet dataSet) {
2
    Log.e("History", "Data returned for Data type: " + dataSet.getDataType().getName());
3
    DateFormat dateFormat = DateFormat.getDateInstance();
4
    DateFormat timeFormat = DateFormat.getTimeInstance();
5
6
    for (DataPoint dp : dataSet.getDataPoints()) {
7
        Log.e("History", "Data point:");
8
        Log.e("History", "\tType: " + dp.getDataType().getName());
9
        Log.e("History", "\tStart: " + dateFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)) + " " + timeFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)));
10
        Log.e("History", "\tEnd: " + dateFormat.format(dp.getEndTime(TimeUnit.MILLISECONDS)) + " " + timeFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)));
11
        for(Field field : dp.getDataType().getFields()) {
12
            Log.e("History", "\tField: " + field.getName() +
13
                    " Value: " + dp.getValue(field));
14
        }
15
    }
16
}

Nếu một ứng dụng trên thiết bị của người dùng đã bật Recording API trong tuần trước đó, thì bạn nhận được dữ liệu cho mỗi ngày mà nó hoạt động. Các bản ghi từ các code ở trên sẽ trông như thế này:

1
E/History: Range Start: Feb 17, 2016
2
E/History: Range End: Feb 24, 2016
3
E/History: Number of buckets: 7
4
E/History: Data returned for Data type: com.google.step_count.delta
5
E/History: Data point:
6
E/History:  Type: com.google.step_count.delta
7
E/History:  Start: Feb 17, 2016 11:01:46 PM
8
E/History:  End: Feb 17, 2016 11:01:46 PM
9
E/History:  Field: steps Value: 9360
10
E/History: Data returned for Data type: com.google.step_count.delta
11
E/History: Data returned for Data type: com.google.step_count.delta
12
E/History: Data returned for Data type: com.google.step_count.delta
13
E/History: Data point:
14
E/History:  Type: com.google.step_count.delta
15
E/History:  Start: Feb 21, 2016 9:58:03 AM
16
E/History:  End: Feb 21, 2016 9:58:03 AM
17
E/History:  Field: steps Value: 10041
18
E/History: Data returned for Data type: com.google.step_count.delta
19
E/History: Data point:
20
E/History:  Type: com.google.step_count.delta
21
E/History:  Start: Feb 21, 2016 11:22:53 PM
22
E/History:  End: Feb 22, 2016 11:22:53 PM
23
E/History:  Field: steps Value: 10786
24
E/History: Data returned for Data type: com.google.step_count.delta
25
E/History: Data point:
26
E/History:  Type: com.google.step_count.delta
27
E/History:  Start: Feb 22, 2016 11:06:31 PM
28
E/History:  End: Feb 23, 2016 11:06:31 PM
29
E/History:  Field: steps Value: 13099
30
E/History: Data returned for Data type: com.google.step_count.delta
31
E/History: Data point:
32
E/History:  Type: com.google.step_count.delta
33
E/History:  Start: Feb 23, 2016 11:02:31 PM
34
E/History:  End: Feb 24, 2016 11:02:31 PM
35
E/History:  Field: steps Value: 9765

Bước 2: Hiển thị dữ liệu cho hôm nay

Bây giờ bạn đã biết cách làm thế nào để lấy dữ liệu Google Fit dựa trên một khung thời gian. Một trường hợp sử dụng mà các nhà phát triển thường gặp là cần dữ liệu cho ngày hiện tại. May mắn thay, Google đã làm cho điều này trở nên dễ dàng bằng cách gọi Fitness.HistoryApi.readDailyTotal, nó tạo ra một đối tượng DailyTotalResult chứa dữ liệu thu thập được trong ngày.

1
private void displayStepDataForToday() {
2
    DailyTotalResult result = Fitness.HistoryApi.readDailyTotal( mGoogleApiClient, DataType.TYPE_STEP_COUNT_DELTA ).await(1, TimeUnit.MINUTES);
3
    showDataSet(result.getTotal());
4
}

Đoạn code ở trên ghi lại dữ liệu bước đi của người dùng trong ngày.

1
E/History: Data returned for Data type: com.google.step_count.delta
2
E/History: Data point:
3
E/History:     Type: com.google.step_count.delta
4
E/History:     Start: Feb 24, 2016 8:39:59 AM
5
E/History:     End: Feb 24, 2016 8:39:59 AM
6
E/History:     Field: steps Value: 9474

Bước 3: Chèn dữ liệu vào Google Fit

Khả năng đọc dữ liệu từ Google Fit là quan trọng, nhưng có thể đôi khi bạn cần phải thêm dữ liệu thu thập được của riêng bạn vào dữ liệu lưu trữ của Google Fit. Để làm điều này, bạn chọn một khoảng thời gian cho dữ liệu và tạo ra một đối tượng DataSource đại diện cho các loại thông tin mà bạn đưa vào Google Fit. Tiếp theo, bạn tạo một đối tượng DataSet và đặt một Datapoint mới vào đó cho hoạt động chèn.

Đối với ví dụ này, chúng ta sẽ giả sử người dùng đã đi bộ một triệu bước, hoặc khoảng 500 dặm, và chèn dữ liệu bước đi thô đó vào giờ cuối cùng của hoạt động của người dùng.

Điều quan trọng cần lưu ý là nếu bạn chọn một khoảng thời gian kéo dài nhiều ngày, số lượng các bước đi mà bạn chèn được phân bố đều trong những ngày đó.

1
Calendar cal = Calendar.getInstance();
2
Date now = new Date();
3
cal.setTime(now);
4
long endTime = cal.getTimeInMillis();
5
cal.add(Calendar.HOUR_OF_DAY, -1);
6
long startTime = cal.getTimeInMillis();
7
8
DataSource dataSource = new DataSource.Builder()
9
    .setAppPackageName(this)
10
    .setDataType(DataType.TYPE_STEP_COUNT_DELTA)
11
    .setName("Step Count")
12
    .setType(DataSource.TYPE_RAW)
13
    .build();
14
    
15
int stepCountDelta = 1000000;
16
DataSet dataSet = DataSet.create(dataSource);
17
18
DataPoint point = dataSet.createDataPoint()
19
        .setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS);
20
point.getValue(Field.FIELD_STEPS).setInt(stepCountDelta);
21
dataSet.add(point);

Sau khi tạo đối tượng DataSet, bạn có thể chèn nó vào kho dữ liệu của Google Fit bằng cách gọi insertData của History API.

1
Fitness.HistoryApi.insertData(mGoogleApiClient, dataSet).await(1, TimeUnit.MINUTES);

Nếu bạn chèn số bước đi của người dùng và sau đó đọc nhật ký hoạt động, bạn sẽ thấy một điều tương tự như sau:

1
E/History: Data returned for Data type: com.google.step_count.delta
2
E/History: Data point:
3
E/History:     Type: com.google.step_count.delta
4
E/History:   Start: Feb 27, 2016 10:05:18 PM
5
E/History: 	End: Feb 28, 2016 10:05:18 PM
6
E/History: 	Field: steps Value: 1008747

Bước 4: Cập nhật dữ liệu trên Google Fit

Khi bạn đã chèn dữ liệu vào trong Google Fit, bạn không thể chèn thêm bất kỳ dữ liệu nào của kiểu dữ liệu đó nếu nó trùng với dữ liệu hiện có. Điều này có thể gây ra vấn đề nếu người dùng đã đi 500 dặm và sau đó đi hơn 500.

Để giải quyết điều này, bạn cần gọi UpdateData. May mắn thay, việc cập nhật dữ liệu là gần như tương tự việc chèn dữ liệu mới, ngoại trừ việc bạn tạo ra một DataUpdateRequest để thay thế.

1
Calendar cal = Calendar.getInstance();
2
Date now = new Date();
3
cal.setTime(now);
4
long endTime = cal.getTimeInMillis();
5
cal.add(Calendar.HOUR_OF_DAY, -1);
6
long startTime = cal.getTimeInMillis();
7
8
DataSource dataSource = new DataSource.Builder()
9
        .setAppPackageName(this)
10
        .setDataType(DataType.TYPE_STEP_COUNT_DELTA)
11
        .setName("Step Count")
12
        .setType(DataSource.TYPE_RAW)
13
        .build();
14
15
int stepCountDelta = 2000000;
16
DataSet dataSet = DataSet.create(dataSource);
17
18
DataPoint point = dataSet.createDataPoint()
19
        .setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS);
20
point.getValue(Field.FIELD_STEPS).setInt(stepCountDelta);
21
dataSet.add(point);
22
23
DataUpdateRequest updateRequest = new DataUpdateRequest.Builder().setDataSet(dataSet).setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS).build();
24
Fitness.HistoryApi.updateData(mGoogleApiClient, updateRequest).await(1, TimeUnit.MINUTES);

Nếu bạn đã ghi lại các bước của người dùng cho những ngày sau khi chạy bộ ở trên, bạn sẽ thấy hơn hai triệu bước.

1
E/History: Data returned for Data type: com.google.step_count.delta
2
E/History: Data point:
3
E/History:     Type: com.google.step_count.delta
4
E/History: 	Start: Feb 27, 2016 10:05:18 PM
5
E/History: 	End: Feb 28, 2016 10:05:18 PM
6
E/History: 	Field: steps Value: 2008747

Bước 5: Xóa dữ liệu khỏi Google Fit

Hoạt động sau cùng có sẵn thông qua History API của Google Fit là khả năng xóa dữ liệu mà bạn đã lưu trong Google Fit. Điều này có thể được thực hiện bằng cách chọn một phạm vi ngày, tạo ra một đối tượng DataDeleteRequest, và gọi deleteData từ History API. Mặc dù bạn có thể xóa dữ liệu được chèn của riêng bạn, nhưng dữ liệu được lưu trữ bởi Google Fit thì không được loại bỏ.

1
Calendar cal = Calendar.getInstance();
2
Date now = new Date();
3
cal.setTime(now);
4
long endTime = cal.getTimeInMillis();
5
cal.add(Calendar.DAY_OF_YEAR, -1);
6
long startTime = cal.getTimeInMillis();
7
8
DataDeleteRequest request = new DataDeleteRequest.Builder()
9
        .setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
10
        .addDataType(DataType.TYPE_STEP_COUNT_DELTA)
11
        .build();
12
13
Fitness.HistoryApi.deleteData(mGoogleApiClient, request).await(1, TimeUnit.MINUTES);

Tổng kết

Như bạn đã thấy, History API là một công cụ rất mạnh mẽ để truy cập và thao tác với kho lưu trữ dữ liệu của Google Fit. Trong khi các API khác của Google Fit nhằm mục đích thu thập dữ liệu, thì History API cho phép bạn duy trì và truy cập dữ liệu để phân tích. Bây giờ bạn sẽ có thể tạo ra các ứng dụng tuyệt vời tận dụng lợi thế của tính năng này.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.