Advertisement
  1. Code
  2. Android SDK

Google Fit cho Android: Sessions API

Scroll to top
This post is part of a series called Google Fit for Android.
Google Fit for Android: History 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.

Trước đó, trong loạt bài này, chúng ta đã khám phá cách làm thế nào để lưu trữ dữ liệu sức khoẻ thông qua Google Play Services sử dụng Recording API và cách để truy cập và cập nhật dữ liệu thông qua History API. Trong hướng dẫn này, chúng tôi mở rộng những ý tưởng này với Sessions API, cho phép bạn tổ chức dữ liệu hoạt động của theo khoảng thời gian.

Bài này sẽ hướng dẫn bạn đi qua một dự án mẫu minh hoạ cách làm thế nào để làm việc với Sessions API. Dự án hoàn chỉnh 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: Thiết lập 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, hãy sử dụng tên gói mà bạn đăng ký để tạo một ứng dụng Android mới với một Activity rỗng.

Với ứng dụng Android đã đượ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. Trong ví dụ này, tôi cũng có sử dụng thư viện Butter Knife để giảm lượng code cho các listener và tìm kiếm các phần tử View.

1
compile 'com.google.android.gms:play-services-fitness:8.4.0'
2
compile 'com.jakewharton:butterknife:7.0.1'

Một khi bạn đã đồng bộ các phụ thuộc của bạn, hãy mở AndroidManifest.xml và bao gồm quyền ACCESS_FINE_LOCATION. Quyền này cần để đọc dữ liệu phiên từ Google Fit. Mặc dù tôi không đi vào chi tiết trong hướng dẫn này, nhưng cần lưu ý rằng, nếu bạn đang nhắm mục tiêu API level 23 hoặc cao hơn, bạn cần yêu cầu quyền truy cập vị trí từ người dùng.

1
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Tiếp theo, mở activity_main.xml và cập nhật nó để nó bao gồm năm phần tử Button sẽ được sử dụng để minh hoạ một số chức năng của Sessions API. Kết quả cuối cùng sẽ trông giống như sau:

Layout of Buttons Each Representing an Operation for the Sessions APILayout of Buttons Each Representing an Operation for the Sessions APILayout of Buttons Each Representing an Operation for the Sessions API

Một khi layout đã được tạo ra, hãy mở MainActivity.java và kết nối với Google Play Services.

1
public class MainActivity extends AppCompatActivity implements
2
        GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
3
        
4
    private final String SESSION_NAME = "session name";
5
6
    private GoogleApiClient mGoogleApiClient = null;
7
    private Session mSession;
8
9
    @Override
10
    protected void onCreate(Bundle savedInstanceState) {
11
        super.onCreate(savedInstanceState);
12
        setContentView(R.layout.activity_main);
13
        ButterKnife.bind(this);
14
15
        mGoogleApiClient = new GoogleApiClient.Builder(this)
16
                .addApi(Fitness.SESSIONS_API)
17
                .addApi(Fitness.HISTORY_API)
18
                .addScope(new Scope(Scopes.FITNESS_LOCATION_READ_WRITE))
19
                .addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
20
                .addConnectionCallbacks(this)
21
                .enableAutoManage(this, 0, this)
22
                .build();
23
    }
24
25
    @Override
26
    protected void onDestroy() {
27
        super.onDestroy();
28
        ButterKnife.unbind(this);
29
    }
30
    
31
    @Override
32
    public void onConnected(Bundle bundle) {
33
34
    }
35
36
    @Override
37
    public void onConnectionSuspended(int i) {
38
39
    }
40
41
    @Override
42
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
43
44
    }
45
}

Bạn có thể đã nhận thấy rằng bạn đã bao gồm History API cùng với Sessions API. Điều này là cần thiết bởi vì History API được sử dụng để xóa dữ liệu phiên, điều mà chúng ta sẽ thảo luận sau trong hướng dẫn này. Bạn cũng cần phải sử dụng cả hai thuộc tính phạm vi FITNESS_LOCATION_READ_WRITEFITNESS_ACTIVITY_READ_WRITE cho các tính năng của Sessions API mà chúng ta sẽ thảo luận.

Một khi bạn đã thiết lập ứng dụng của bạn để kết nối với Google Play Services và Google Fit, đã đến lúc để bắt đầu thử Sessions API.

2. Sử dụng Sessions API

Sessions API là một công cụ từ Google Fit để lưu trữ dữ liệu sức khoẻ cho người dùng. Như vậy, nó không có ý định thay thế cho Recording hoặc History API, mà thay vào đó là một cách bổ sung để cải thiện ứng dụng của bạn để tạo ra một trải nghiệm người dùng tốt hơn.

Trong phần này, bạn sẽ tìm hiểu cách làm thế nào để bắt đầu và ngừng thu thập dữ liệu phiên theo thời gian thực, cách để chèn một phiên vào kho dữ liệu Google Fit, làm thế nào để đọc dữ liệu phiên được lưu trữ trước đó, và làm thế nào để xóa các phiên không cần thiết hoặc không chính xác. Tương tự như History API, Sessions API phải được gọi bên ngoài tiến trình chính. Trong khi hướng dẫn cho History API gói các hoạt động trong AsyncTask, thì hướng dẫn này sẽ tập trung vào việc sử dụng các hàm callback PendingResult để theo dõi các tác vụ.

Bắt đầu và Dừng một phiên

Trường hợp phổ biến nhất cho Sessions API là ghi lại thông tin sau khi người dùng đã bắt đầu một hoạt động thể chất. Điều này thường được bắt đầu đồng thời với Recording API để dữ liệu cảm biến có thể được liên kết với khung thời gian phiên. Để bắt đầu ghi lại một phiên, bạn cần phải tạo ra một đối tượng session với một cái tên, một định danh duy nhất, một mô tả, một thời điểm bắt đầu, và các loại hoạt động mà người dùng đang thực hiện.

1
mSession = new Session.Builder()
2
        .setName(SESSION_NAME)
3
        .setIdentifier(getString(R.string.app_name) + " " + System.currentTimeMillis())
4
        .setDescription("Yoga Session Description")
5
        .setStartTime(Calendar.getInstance().getTimeInMillis(), TimeUnit.MILLISECONDS)
6
        .setActivity(FitnessActivities.YOGA)
7
        .build();

Một khi đối tượng Session được tạo, bạn có thể gọi startSession trên Sessions API để bắt đầu ghi lại hoạt động của người dùng.

1
PendingResult<Status> pendingResult =
2
        Fitness.SessionsApi.startSession(mGoogleApiClient, mSession);
3
4
pendingResult.setResultCallback(
5
        new ResultCallback<Status>() {
6
            @Override
7
            public void onResult(Status status) {
8
                if (status.isSuccess()) {
9
                    Log.i("Tuts+", "Successfully started session");
10
                } else {
11
                    Log.i("Tuts+", "Failed to start session: " + status.getStatusMessage());
12
                }
13
            }
14
        }
15
);

Khi người dùng của bạn đã kết thúc hoạt động của họ, bạn có thể kết thúc phiên bằng cách gọi stopSession với định danh duy nhất cho Session.

1
PendingResult<SessionStopResult> pendingResult =
2
        Fitness.SessionsApi.stopSession(mGoogleApiClient, mSession.getIdentifier());
3
4
pendingResult.setResultCallback(new ResultCallback<SessionStopResult>() {
5
    @Override
6
    public void onResult(SessionStopResult sessionStopResult) {
7
        if( sessionStopResult.getStatus().isSuccess() ) {
8
            Log.i("Tuts+", "Successfully stopped session");
9
        } else {
10
            Log.i("Tuts+", "Failed to stop session: " +
11
                    sessionStopResult.getStatus().getStatusMessage());
12
        }
13
    }
14
});

Điều đáng chú ý ở đây là đối tượng Session cài đặt giao diện Parcelable, vì vậy nó có thể được lưu trữ trong một Bundle trong trường hợp bạn cần lưu trữ hoặc truyền nó đến một thành phần khác trong ứng dụng của bạn. Điều này có thể hữu ích nếu người dùng bắt đầu một hoạt động và sau đó đóng ứng dụng, khi đó bạn có thể cần dữ liệu phiên đó để dừng việc ghi lại phiên.

Chèn vào Google Fit

Bây giờ thì bạn đã biết cách để ghi lại thông tin về phiên thời gian thực, bước tiếp theo là chèn các phiên sau hoạt động. Trong khi bạn có thể chèn một khối thời gian như là một phiên, thì Sessions API cũng cho phép bạn kết hợp các hoạt động với các phân đoạn của một phiên. Điều này là rất hữu ích cho các tình huống mà người dùng có thể không liên tục thực hiện hoạt động tương tự trong toàn bộ thói quen tập thể thao của họ.

Một ví dụ của việc này có thể là khi ứng dụng của bạn đã phát hiện ra rằng những người dùng của bạn chạy, nghỉ ngơi một thời gian ngắn bằng cách đi bộ, và sau đó chạy một lần nữa. Trong ví dụ sau, bạn chèn một Session mà người dùng chạy trong 15 phút, đi bộ 5 phút, và sau đó chạy trong 15 phút nữa bằng cách theo dõi khi nào người dùng bắt đầu và dừng từng hoạt động. Bạn cũng ghi lại tốc độ trung bình của họ trong từng hoạt động.

1
Calendar calendar = Calendar.getInstance();
2
Date now = new Date();
3
calendar.setTime(now);
4
5
long endTime = calendar.getTimeInMillis();
6
calendar.add(Calendar.MINUTE, -15);
7
long walkEndTime = calendar.getTimeInMillis();
8
calendar.add(Calendar.MINUTE, -5);
9
long walkStartTime = calendar.getTimeInMillis();
10
calendar.add(Calendar.MINUTE, -15);
11
long startTime = calendar.getTimeInMillis();
12
13
float firstRunSpeed = 15;
14
float walkSpeed = 5;
15
float secondRunSpeed = 13;

Một khi bạn có các giá trị khoá thời gian và tốc độ, bạn cần phải tạo ra hai nhóm DataSet để lưu trữ thông tin về các hoạt động và tốc độ. Những điều này có thể được tạo ra từ một bộ các đối tượng DataSource với bộ các thuộc tính DataType.

1
DataSource speedSegmentDataSource = new DataSource.Builder()
2
        .setAppPackageName(this.getPackageName())
3
        .setDataType(DataType.TYPE_SPEED)
4
        .setName("Tuts+ speed dataset")
5
        .setType(DataSource.TYPE_RAW)
6
        .build();
7
8
DataSource activitySegmentDataSource = new DataSource.Builder()
9
        .setAppPackageName(this.getPackageName())
10
        .setDataType(DataType.TYPE_ACTIVITY_SEGMENT)
11
        .setName("Tuts+ activity segments dataset")
12
        .setType(DataSource.TYPE_RAW)
13
        .build();
14
15
DataSet speedDataSet = DataSet.create(speedSegmentDataSource);
16
DataSet activityDataSet = DataSet.create(activitySegmentDataSource);

Tiếp theo, bạn cần phải tạo ra các đối tượng Datapoint sẽ được chèn vào kho dữ liệu Google Fit. Mỗi Datapoint có một khoảng thời gian và một tập hợp các thuộc tính Field lưu trữ dữ liệu có liên quan. Một khi từng Datapoint được cấu hình, bạn cần phải chèn nó vào trong DataSet thích hợp. Để cho ngắn gọn, tôi chỉ hiển thị đoạn code cho việc tạo đối tượng Datapoint cho phân đoạn chạy đầu tiên ở dưới, tuy nhiên, các đối tượng data point khác có trong mã nguồn cho hướng dẫn này trên GitHub.

1
//Create speed data point for first run segment

2
DataPoint firstRunSpeedDataPoint = speedDataSet.createDataPoint()
3
        .setTimeInterval(startTime, walkStartTime, TimeUnit.MILLISECONDS);
4
firstRunSpeedDataPoint.getValue(Field.FIELD_SPEED).setFloat(firstRunSpeed);
5
speedDataSet.add(firstRunSpeedDataPoint);
6
7
//Create activity data point for second run segment

8
DataPoint secondRunActivityDataPoint = activityDataSet.createDataPoint()
9
        .setTimeInterval(walkEndTime, endTime, TimeUnit.MILLISECONDS);
10
secondRunActivityDataPoint.getValue(Field.FIELD_ACTIVITY).setActivity(FitnessActivities.RUNNING);
11
activityDataSet.add(secondRunActivityDataPoint);

Một khi bạn đã di trú hai nhóm DataSet, đã đến lúc để tạo ra Session mà bạn sẽ chèn. Session này sẽ cần phải được đặt tên, định danh duy nhất, mô tả, thời điểm bắt đầu và kết thúc, và các thuộc tính hoạt động. Một điều quan trọng cần phải lưu ý là tên mà bạn sử dụng khi chèn một Session là tên mà bạn cần sử dụng khi cố gắng đọc phiên này sau đó.

1
Session session = new Session.Builder()
2
        .setName(SESSION_NAME)
3
        .setIdentifier(getString(R.string.app_name) + " " + System.currentTimeMillis())
4
        .setDescription("Running in Segments")
5
        .setStartTime(startTime, TimeUnit.MILLISECONDS)
6
        .setEndTime(endTime, TimeUnit.MILLISECONDS)
7
        .setActivity(FitnessActivities.RUNNING)
8
        .build();

Bây giờ Session của bạn đã được tạo ra, bạn cần phải tạo một SessionInsertRequest, thêm các đối tượng DataSet của bạn vào nó, và sau đó chèn Session đó vào Google Fit.

1
SessionInsertRequest insertRequest = new SessionInsertRequest.Builder()
2
        .setSession(session)
3
        .addDataSet(speedDataSet)
4
        .addDataSet(activityDataSet)
5
        .build();
6
7
PendingResult<Status> pendingResult =
8
        Fitness.SessionsApi.insertSession(mGoogleApiClient, insertRequest);
9
10
pendingResult.setResultCallback(new ResultCallback<Status>() {
11
    @Override
12
    public void onResult(Status status) {
13
        if( status.isSuccess() ) {
14
            Log.i("Tuts+", "successfully inserted running session");
15
        } else {
16
            Log.i("Tuts+", "Failed to insert running session: " + status.getStatusMessage());
17
        }
18
    }
19
});

Đọc dữ liệu cảm biến

Không quan trọng là có bao nhiêu dữ liệu phiên mà bạn lưu trữ với ứng dụng của bạn, nó sẽ không là gì trừ khi bạn có thể đọc dữ liệu đó và sử dụng nó để làm cho ứng dụng của bạn tốt hơn cho người dùng của bạn. May mắn thay, Google Fit giúp vô cùng dễ dàng để nhận dữ liệu phiên trong một khung thời gian quy định.

Trước tiên, bạn cần phải chọn thời điểm bắt đầu và kết thúc cho dữ liệu mà bạn muốn nhận. Trong ví dụ này, chúng ta yêu cầu dữ liệu phiên của tháng trước.

1
Calendar cal = Calendar.getInstance();
2
Date now = new Date();
3
cal.setTime(now);
4
long endTime = cal.getTimeInMillis();
5
cal.add(Calendar.MONTH, -1);
6
long startTime = cal.getTimeInMillis();

Một khi cửa sổ thời gian của bạn đã được lựa chọn, bạn cần phải tạo ra một SessionReadRequest. Yêu cầu này bao gồm khoảng thời gian cho dữ liệu phiên mong muốn của bạn, loại dữ liệu phiên mà bạn đang tìm kiếm (hướng dẫn này sẽ chỉ tìm các dữ liệu về tốc độ), và tên của các phiên mà bạn đang yêu cầu, tuy nhiên, khoảng thời gian là thuộc tính cần thiết duy nhất.

1
SessionReadRequest readRequest = new SessionReadRequest.Builder()
2
        .setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
3
        .read(DataType.TYPE_SPEED)
4
        .setSessionName(SESSION_NAME)
5
        .build();
6
7
PendingResult<SessionReadResult> sessionReadResult =
8
        Fitness.SessionsApi.readSession(mGoogleApiClient, readRequest);

Sau khi bạn đã gọi SessionsApi.readSession, bạn nhận được một đối tượng SessionReadResult có chứa danh sách các đối tượng SessionDataSet mà bạn có thể sử dụng trong ứng dụng của bạn. Đối với hướng dẫn này, chúng ta chỉ đơn giản là log dữ liệu.

1
sessionReadResult.setResultCallback(new ResultCallback<SessionReadResult>() {
2
    @Override
3
    public void onResult(SessionReadResult sessionReadResult) {
4
        if (sessionReadResult.getStatus().isSuccess()) {
5
            Log.i("Tuts+", "Successfully read session data");
6
            for (Session session : sessionReadResult.getSessions()) {
7
                Log.i("Tuts+", "Session name: " + session.getName());
8
                for (DataSet dataSet : sessionReadResult.getDataSet(session)) {
9
                    for (DataPoint dataPoint : dataSet.getDataPoints()) {
10
                        Log.i("Tuts+", "Speed: " + dataPoint.getValue(Field.FIELD_SPEED));
11
                    }
12
                }
13
            }
14
        } else {
15
            Log.i("Tuts+", "Failed to read session data");
16
        }
17
    }
18
});

Nếu bạn chạy ứng dụng của bạn ngay bây giờ và sử dụng các hoạt động chèn và đọc, thì bạn sẽ nhận được ba đối tượng tốc độ Datapoint mà bạn đã tạo trong phần trước.

1
I/Tuts+: Speed: 15.0
2
I/Tuts+: Speed: 5.0
3
I/Tuts+: Speed: 13.0

Xoá dữ liệu phiên

Có thể đôi khi bạn cần phải xóa một số thông tin về phiên mà không chính xác hoặc không cần thiết. Điều này có thể được thực hiện bằng cách sử dụng History API để xóa phiên đã được lưu lại trong kho dữ liệu Google Fit.

Trước tiên, bạn cần phải xác định một khoảng thời gian cho hoạt động xóa. Sau đó bạn có thể thêm thông tin bổ sung, chẳng hạn như một DataType hoặc các thuộc tính Session khác để xóa, hoặc bạn có thể chỉ cần xóa tất cả các dữ liệu phiên trong khoảng thời gian.

1
Calendar calendar = Calendar.getInstance();
2
Date now = new Date();
3
calendar.setTime(now);
4
long endTime = calendar.getTimeInMillis();
5
calendar.add(Calendar.DAY_OF_YEAR, -1);
6
long startTime = calendar.getTimeInMillis();
7
8
DataDeleteRequest request = new DataDeleteRequest.Builder()
9
        .setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
10
        .addDataType(DataType.TYPE_SPEED)
11
        .deleteAllSessions()
12
        .build();
13
14
PendingResult<Status> deleteRequest = Fitness.HistoryApi.deleteData(mGoogleApiClient, request);
15
deleteRequest.setResultCallback(new ResultCallback<Status>() {
16
    @Override
17
    public void onResult(@NonNull Status status) {
18
        if( status.isSuccess() ) {
19
            Log.i("Tuts+", "Successfully deleted sessions");
20
        } else {
21
            Log.i("Tuts+", "Failed to delete sessions");
22
        }
23
    }
24
});

Tổng kết

Như bạn đã học được trong hướng dẫn này, Sessions API là một công cụ mạnh mẽ cho việc tổ chức dữ liệu thu thập được trong các khối thời gian. Đó là một lời đáp lại tuyệt vời đối với các API khác của Google Fit. Khi được sử dụng kết hợp với History và Recording API, có rất nhiều thứ mà bạn có thể làm để hiểu được hoạt động của người dùng sử dụng ứng dụng của bạn và cung cấp cho họ một trải nghiệm tuyệt vời với các ứng dụng theo dõi sức khoẻ của bạn.

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.