Hướng dẫn này tương thích với Health Connect phiên bản 1.1.0-alpha12.
Với tuyến đường tập thể dục, người dùng có thể theo dõi tuyến đường qua GPS cho các hoạt động tập thể dục được liên kết và chia sẻ bản đồ trong bài tập của họ với các ứng dụng khác.
Hướng dẫn này cung cấp thông tin về cách yêu cầu người dùng cấp quyền, đồng thời trình bày cách các ứng dụng tiếp nhận quyền ghi dữ liệu về tuyến đường trong phiên tập thể dục.
Chức năng đọc và ghi đối với các tuyến đường tập thể dục bao gồm:
- Các ứng dụng tạo một quyền ghi mới cho các tuyến đường tập thể dục.
- Trường hợp chèn xảy ra bằng cách ghi một phiên tập thể dục có một tuyến đường làm trường của phiên đó.
- Đọc:
- Đối với chủ sở hữu phiên, dữ liệu được truy cập bằng cách dùng một lần đọc phiên.
- Từ ứng dụng của bên thứ ba, thông qua một hộp thoại cho phép người dùng cấp quyền đọc một lần đối với tuyến đường.
Nếu người dùng không có quyền ghi và tuyến đường chưa được thiết lập, thì tuyến đường này sẽ không cập nhật.
Nếu ứng dụng của bạn có quyền ghi tuyến đường và tìm cách cập nhật một phiên bằng cách truyền đối tượng phiên nhưng không có tuyến đường, thì tuyến đường hiện có sẽ bị xoá.
Phạm vi cung cấp tính năng
Không có cờ về tính năng cho kiểu dữ liệu này.
Các quyền bắt buộc
Quyền truy cập vào lộ trình tập luyện được bảo vệ bằng các quyền sau:
android.permission.health.READ_EXERCISE_ROUTE
android.permission.health.WRITE_EXERCISE_ROUTE
Để thêm chức năng tuyến đường tập thể dục vào ứng dụng của bạn, hãy bắt đầu bằng cách yêu cầu quyền ghi cho kiểu dữ liệu ExerciseSession
.
Dưới đây là quyền bạn cần khai báo để có thể ghi tuyến đường tập thể dục:
<application>
<uses-permission
android:name="android.permission.health.WRITE_EXERCISE_ROUTE" />
...
</application>
Để đọc tuyến đường tập thể dục, bạn cần yêu cầu các quyền sau:
<application>
<uses-permission
android:name="android.permission.health.READ_EXERCISE_ROUTE" />
...
</application>
Bạn cũng phải khai báo quyền đối với bài tập thể dục, vì mỗi tuyến đường được liên kết với một phiên tập thể dục (một phiên = một bài tập).
Để yêu cầu cấp quyền, hãy sử dụng phương thức PermissionController.createRequestPermissionResultContract()
khi bạn lần đầu kết nối ứng dụng của mình với Health Connect. Dưới đây là một số quyền mà bạn có thể muốn yêu cầu:
- Đọc dữ liệu sức khoẻ, bao gồm cả dữ liệu tuyến đường:
HealthPermission.getReadPermission(ExerciseSessionRecord::class)
- Ghi dữ liệu sức khoẻ, bao gồm cả dữ liệu tuyến đường:
HealthPermission.getWritePermission(ExerciseSessionRecord::class)
- Ghi dữ liệu tuyến đường tập thể dục:
HealthPermission.PERMISSION_WRITE_EXERCISE_ROUTE
Yêu cầu người dùng cấp quyền
Sau khi tạo một phiên bản ứng dụng, ứng dụng của bạn cần yêu cầu người dùng cấp quyền. Người dùng phải được phép cấp hoặc từ chối cấp quyền bất cứ lúc nào.
Để thực hiện việc này, hãy tạo một tập hợp quyền cho các kiểu dữ liệu bắt buộc. Trước tiên, bạn cần khai báo các quyền trong tập hợp này ở tệp kê khai Android.
// Create a set of permissions for required data types
val PERMISSIONS =
setOf(
HealthPermission.getReadPermission(ExerciseSessionRecord::class),
HealthPermission.getWritePermission(ExerciseSessionRecord::class)
)
Hãy sử dụng getGrantedPermissions
để xem ứng dụng của bạn đã được cấp các quyền cần thiết chưa. Nếu chưa, hãy sử dụng createRequestPermissionResultContract
để yêu cầu các quyền đó. Thao tác này sẽ hiện màn hình các quyền của Health Connect.
// Create the permissions launcher
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()
val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
if (granted.containsAll(PERMISSIONS)) {
// Permissions successfully granted
} else {
// Lack of required permissions
}
}
suspend fun checkPermissionsAndRun(healthConnectClient: HealthConnectClient) {
val granted = healthConnectClient.permissionController.getGrantedPermissions()
if (granted.containsAll(PERMISSIONS)) {
// Permissions already granted; proceed with inserting or reading data
} else {
requestPermissions.launch(PERMISSIONS)
}
}
Vì người dùng có thể cấp hoặc thu hồi quyền bất cứ lúc nào, nên ứng dụng của bạn cần kiểm tra định kỳ các quyền đã cấp và xử lý các tình huống khi mất quyền.
Thông tin có trong bản ghi phiên tập thể dục
Mỗi bản ghi phiên tập thể dục chứa những thông tin sau:
- Loại bài tập, ví dụ: đạp xe.
- Tuyến đường tập thể dục, chứa các thông tin như vĩ độ, kinh độ và độ cao.
Các phép tổng hợp được hỗ trợ
Không có phép tổng hợp nào được hỗ trợ cho loại dữ liệu này.
Ví dụ về cách sử dụng
Các đoạn mã sau đây cho biết cách đọc và ghi một tuyến đường tập thể dục.
Đọc dữ liệu về tuyến đường tập thể dục
Ứng dụng của bạn không thể đọc dữ liệu tuyến đường tập thể dục do các ứng dụng khác tạo khi chạy ở chế độ nền.
Khi ứng dụng của bạn chạy ở chế độ nền và cố gắng đọc một tuyến đường tập thể dục do một ứng dụng khác tạo, Health Connect sẽ trả về một phản hồi ExerciseRouteResult.ConsentRequired
, ngay cả khi ứng dụng của bạn có quyền truy cập Luôn cho phép vào dữ liệu tuyến đường tập thể dục.
Vì lý do này, bạn nên yêu cầu các tuyến đường khi người dùng tương tác có chủ ý với ứng dụng của bạn, khi người dùng đang tích cực tương tác với giao diện người dùng của ứng dụng.
Để tìm hiểu thêm về hoạt động đọc ở chế độ nền, hãy xem Ví dụ về hoạt động đọc ở chế độ nền.
Đoạn mã sau đây minh hoạ cách đọc một phiên trong Health Connect và yêu cầu dữ liệu về tuyến đường từ phiên đó:
suspend fun readExerciseSessionAndRoute() {
val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofHours(1))
val grantedPermissions =
healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
HealthPermission.getReadPermission(ExerciseSessionRecord::class))) {
// The user doesn't allow the app to read exercise session data.
return
}
val readResponse =
healthConnectClient.readRecords(
ReadRecordsRequest(
ExerciseSessionRecord::class,
TimeRangeFilter.between(startTime, endTime)
)
)
val exerciseRecord = readResponse.records.first()
val recordId = exerciseRecord.metadata.id
// See https://developer.android.com/training/basics/intents/result#launch
// for appropriately handling ActivityResultContract.
val requestExerciseRouteLauncher = fragment.registerForActivityResul
(ExerciseRouteRequestContract()) { exerciseRoute: ExerciseRoute? ->
if (exerciseRoute != null) {
displayExerciseRoute(exerciseRoute)
} else {
// Consent was denied
}
}
val exerciseSessionRecord =
healthConnectClient.readRecord(ExerciseSessionRecord::class, recordId).record
when (val exerciseRouteResult = exerciseSessionRecord.exerciseRouteResult) {
is ExerciseRouteResult.Data ->
displayExerciseRoute(exerciseRouteResult.exerciseRoute)
is ExerciseRouteResult.ConsentRequired ->
requestExerciseRouteLauncher.launch(recordId)
is ExerciseRouteResult.NoData -> Unit // No exercise route to show
else -> Unit
}
}
fun displayExerciseRoute(route: ExerciseRoute?) {
val locations = route.route.orEmpty()
for (location in locations) {
// Handle location.
}
}
Ghi dữ liệu về tuyến đường tập thể dục
Mã sau đây minh hoạ cách ghi lại một phiên có dữ liệu về tuyến đường tập thể dục:
suspend fun InsertExerciseRoute(healthConnectClient: HealthConnectClient) {
val grantedPermissions =
healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
getWritePermission(ExerciseSessionRecord::class))) {
// The user doesn't allow the app to write exercise session data.
return
}
val sessionStartTime = Instant.now()
val sessionDuration = Duration.ofMinutes(20)
val sessionEndTime = sessionStartTime.plus(sessionDuration)
val exerciseRoute =
if (grantedPermissions.contains(PERMISSION_WRITE_EXERCISE_ROUTE)) ExerciseRoute(
listOf(
ExerciseRoute.Location(
// Location times must be on or after the session start time
time = sessionStartTime,
latitude = 6.5483,
longitude = 0.5488,
horizontalAccuracy = Length.meters(2.0),
verticalAccuracy = Length.meters(2.0),
altitude = Length.meters(9.0),
), ExerciseRoute.Location(
// Location times must be before the session end time
time = sessionEndTime.minusSeconds(1),
latitude = 6.4578,
longitude = 0.6577,
horizontalAccuracy = Length.meters(2.0),
verticalAccuracy = Length.meters(2.0),
altitude = Length.meters(9.2),
)
)
)
else
// The user doesn't allow the app to write exercise route data.
null
val exerciseSessionRecord = ExerciseSessionRecord(
startTime = sessionStartTime,
startZoneOffset = ZoneOffset.UTC,
endTime = sessionEndTime,
endZoneOffset = ZoneOffset.UTC,
exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_BIKING,
title = "Morning Bike Ride",
exerciseRoute = exerciseRoute,
metadata = Metadata.manualEntry(
device = Device(type = Device.TYPE_PHONE)
),
)
val response = healthConnectClient.insertRecords(listOf(exerciseSessionRecord))
}
Phiên hoạt động tập thể dục
Phiên hoạt động tập thể dục có thể gồm mọi hoạt động từ chạy bộ đến chơi cầu lông.
Ghi phiên hoạt động tập thể dục
Dưới đây là cách tạo yêu cầu chèn kèm theo dữ liệu trong phiên hoạt động:
suspend fun writeExerciseSession(healthConnectClient: HealthConnectClient) {
healthConnectClient.insertRecords(
listOf(
ExerciseSessionRecord(
startTime = START_TIME,
startZoneOffset = START_ZONE_OFFSET,
endTime = END_TIME,
endZoneOffset = END_ZONE_OFFSET,
exerciseType = ExerciseSessionRecord.ExerciseType.RUNNING,
title = "My Run"
),
// ... other records
)
)
}
Đọc phiên hoạt động tập thể dục
Dưới đây là ví dụ về cách đọc một phiên hoạt động tập thể dục:
suspend fun readExerciseSessions(
healthConnectClient: HealthConnectClient,
startTime: Instant,
endTime: Instant
) {
val response =
healthConnectClient.readRecords(
ReadRecordsRequest(
ExerciseSessionRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
for (exerciseRecord in response.records) {
// Process each exercise record
// Optionally pull in with other data sources of the same time range.
val distanceRecord =
healthConnectClient
.readRecords(
ReadRecordsRequest(
DistanceRecord::class,
timeRangeFilter =
TimeRangeFilter.between(
exerciseRecord.startTime,
exerciseRecord.endTime
)
)
)
.records
}
}
Ghi dữ liệu loại phụ
Phiên hoạt động cũng có thể có dữ liệu loại phụ không bắt buộc, làm phiên phong phú thêm bằng thông tin bổ sung.
Ví dụ: các phiên hoạt động tập thể dục có thể có các lớp ExerciseSegment
, ExerciseLap
và ExerciseRoute
:
val segments = listOf(
ExerciseSegment(
startTime = Instant.parse("2022-01-02T10:10:10Z"),
endTime = Instant.parse("2022-01-02T10:10:13Z"),
segmentType = ActivitySegmentType.BENCH_PRESS,
repetitions = 373
)
)
val laps = listOf(
ExerciseLap(
startTime = Instant.parse("2022-01-02T10:10:10Z"),
endTime = Instant.parse("2022-01-02T10:10:13Z"),
length = 0.meters
)
)
ExerciseSessionRecord(
exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_CALISTHENICS,
startTime = Instant.parse("2022-01-02T10:10:10Z"),
endTime = Instant.parse("2022-01-02T10:10:13Z"),
startZoneOffset = ZoneOffset.UTC,
endZoneOffset = ZoneOffset.UTC,
segments = segments,
laps = laps,
route = route
)
Xoá phiên hoạt động tập thể dục
Có hai cách để xoá phiên hoạt động tập thể dục:
- Theo phạm vi thời gian.
- Bằng UID.
Dưới đây là cách xoá dữ liệu loại phụ theo phạm vi thời gian:
suspend fun deleteExerciseSessionByTimeRange(
healthConnectClient: HealthConnectClient,
exerciseRecord: ExerciseSessionRecord,
) {
val timeRangeFilter = TimeRangeFilter.between(exerciseRecord.startTime, exerciseRecord.endTime)
healthConnectClient.deleteRecords(ExerciseSessionRecord::class, timeRangeFilter)
// delete the associated distance record
healthConnectClient.deleteRecords(DistanceRecord::class, timeRangeFilter)
}
Bạn cũng có thể xoá dữ liệu loại phụ bằng UID. Nếu làm như vậy, bạn sẽ chỉ xoá phiên hoạt động tập thể dục mà không xoá được dữ liệu liên quan:
suspend fun deleteExerciseSessionByUid(
healthConnectClient: HealthConnectClient,
exerciseRecord: ExerciseSessionRecord,
) {
healthConnectClient.deleteRecords(
ExerciseSessionRecord::class,
recordIdsList = listOf(exerciseRecord.metadata.id),
clientRecordIdsList = emptyList()
)
}