Nếu muốn tạo trải nghiệm theo dõi giấc ngủ trong ứng dụng, bạn có thể dùng Health Connect để làm những việc như:
- Ghi dữ liệu về phiên giấc ngủ
- Ghi dữ liệu về giai đoạn ngủ
- Ghi dữ liệu giấc ngủ, chẳng hạn như tần số tim, độ bão hòa oxy và nhịp thở
- Đọc dữ liệu giấc ngủ từ các ứng dụng khác
Hướng dẫn này mô tả cách tạo các tính năng về giấc ngủ này, bao gồm các loại dữ liệu, quá trình thực thi ở chế độ nền, quyền, quy trình công việc được đề xuất và các phương pháp hay nhất.
Tổng quan: Xây dựng một trình theo dõi giấc ngủ toàn diện
Bạn có thể xây dựng trải nghiệm theo dõi giấc ngủ toàn diện bằng Health Connect bằng cách làm theo các bước chính sau:
- Triển khai chính xác các quyền dựa trên Quyền truy cập vào dữ liệu sức khoẻ.
- Ghi lại các phiên bằng
SleepSessionRecord. - Ghi các loại dữ liệu như giai đoạn ngủ, tần số tim và độ bão hòa oxy một cách nhất quán trong phiên.
- Quản lý đúng cách việc thực thi trong nền để xác minh việc liên tục thu thập dữ liệu qua đêm.
- Đọc dữ liệu phiên để xem bản tóm tắt và phân tích sau giấc ngủ.
Quy trình này cho phép khả năng tương tác với các ứng dụng Health Connect khác và xác minh quyền truy cập dữ liệu do người dùng kiểm soát.
Trước khi bắt đầu
Trước khi triển khai các tính năng liên quan đến giấc ngủ:
- Tích hợp Health Connect bằng cách sử dụng phần phụ thuộc phù hợp.
- Tạo một thực thể
HealthConnectClient. - Xác minh rằng ứng dụng của bạn triển khai các quy trình cấp quyền khi bắt đầu chạy dựa trên HealthPermissions (Quyền truy cập vào dữ liệu sức khoẻ).
Khái niệm chính
Health Connect biểu thị dữ liệu giấc ngủ bằng một số thành phần cốt lõi. SleepSessionRecord đóng vai trò là bản ghi trung tâm cho giấc ngủ, chứa các thông tin chi tiết như thời gian bắt đầu hoặc kết thúc và các giai đoạn ngủ. Trong một phiên, nhiều loại dữ liệu như HeartRateRecord hoặc OxygenSaturationRecord có thể được ghi lại.
Phiên giấc ngủ
Dữ liệu giấc ngủ được biểu thị bằng SleepSessionRecord. Mỗi bản ghi lưu trữ:
startTimeendTimestages: Danh sáchSleepSessionRecord.Stagebao gồm giấc ngủ sâu, giấc ngủ nông, giấc ngủ REM và giấc ngủ thức.- Siêu dữ liệu không bắt buộc của phiên (tiêu đề, ghi chú)
Các ứng dụng có thể ghi nhiều loại dữ liệu liên kết với một phiên.
Loại dữ liệu
Các loại dữ liệu phổ biến được ghi lại trong một phiên ngủ bao gồm:
SleepSessionRecord: Ghi lại thời lượng và các giai đoạn ngủ, bao gồm cả ngủ sâu, ngủ nông, ngủ REM và thức giấc.HeartRateRecord: Ghi lại tần số tim trong khi ngủ.OxygenSaturationRecord: Ghi lại độ bão hoà oxy (SpO2) trong khi ngủ.RespiratoryRateRecord: Ghi lại nhịp thở trong khi ngủ.
Mỗi loại dữ liệu được lưu trữ dưới dạng một bản ghi riêng lẻ.
Điều cần cân nhắc khi phát triển ứng dụng
Các ứng dụng theo dõi giấc ngủ thường cần chạy trong thời gian dài, thường xuyên ở chế độ nền khi màn hình tắt. Khi xây dựng các tính năng về giấc ngủ, bạn cần cân nhắc cách quản lý việc thực thi ở chế độ nền và yêu cầu các quyền cần thiết đối với dữ liệu giấc ngủ.
Chạy ở chế độ nền
Các ứng dụng theo dõi giấc ngủ thường chạy qua đêm khi màn hình tắt. Khi ở trạng thái này, bạn nên sử dụng:
- Dịch vụ trên nền trước để thu thập dữ liệu
WorkManagerđể ghi hoặc đồng bộ hoá bị hoãn lại- Chiến lược xử lý hàng loạt để ghi dữ liệu chi tiết thường xuyên, chẳng hạn như nhịp tim
Duy trì tính liên tục bằng cách giữ mã phiên nhất quán trên tất cả các lượt ghi.
Quyền
Ứng dụng của bạn phải yêu cầu các quyền liên quan của Health Connect trước khi đọc hoặc ghi dữ liệu giấc ngủ. Để xem danh sách đầy đủ các loại dữ liệu, hãy xem Các loại dữ liệu của Health Connect. Các quyền thường dùng cho giấc ngủ bao gồm phiên ngủ và các chỉ số như tần số tim hoặc độ bão hòa oxy.
Quyền truy cập vào dữ liệu giấc ngủ được bảo vệ bằng các quyền sau:
android.permission.health.READ_SLEEPandroid.permission.health.WRITE_SLEEP
Để thêm chức năng theo dõi giấc ngủ vào ứng dụng, hãy bắt đầu bằng cách yêu cầu quyền cho kiểu dữ liệu SleepSession.
Dưới đây là quyền bạn cần khai báo để có thể ghi dữ liệu về giấc ngủ:
<application>
<uses-permission
android:name="android.permission.health.WRITE_SLEEP" />
...
</application>
Để đọc dữ liệu về giấc ngủ, bạn cần yêu cầu các quyền sau:
<application>
<uses-permission
android:name="android.permission.health.READ_SLEEP" />
...
</application>
Sau đây là ví dụ về cách yêu cầu quyền cho một phiên ngủ bao gồm dữ liệu về tần số tim, độ bão hòa oxy và nhịp thở:
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(SleepSessionRecord::class),
HealthPermission.getWritePermission(SleepSessionRecord::class),
HealthPermission.getReadPermission(HeartRateRecord::class),
HealthPermission.getWritePermission(HeartRateRecord::class),
HealthPermission.getReadPermission(OxygenSaturationRecord::class),
HealthPermission.getWritePermission(OxygenSaturationRecord::class),
HealthPermission.getReadPermission(RespiratoryRateRecord::class),
HealthPermission.getWritePermission(RespiratoryRateRecord::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 quyền mỗi khi sử dụng và xử lý các trường hợp mất quyền.
Triển khai một phiên giấc ngủ
Phần này mô tả quy trình được đề xuất để ghi lại dữ liệu giấc ngủ.
Để căn chỉnh các kiểu dữ liệu như HeartRateRecord hoặc OxygenSaturationRecord với một giấc ngủ, hãy ghi lại các kiểu dữ liệu đó bằng dấu thời gian nằm trong khoảng startTime và endTime của giấc ngủ. Health Connect không sử dụng giá trị nhận dạng phiên để liên kết các phiên ngủ với dữ liệu chi tiết. Thay vào đó, mối liên kết được ngầm hiểu thông qua các khoảng thời gian trùng nhau. Khi đọc dữ liệu giấc ngủ, bạn có thể sử dụng phạm vi thời gian của một phiên để truy vấn các kiểu dữ liệu được liên kết, như minh hoạ trong phần Đọc dữ liệu giấc ngủ.
Ghi một phiên
Mặc dù dữ liệu thật chi tiết như tần số tim có thể được ghi lại trong suốt một giấc ngủ, nhưng bản thân SleepSessionRecord chỉ được ghi vào Health Connect sau khi giấc ngủ kết thúc, chẳng hạn như khi người dùng thức dậy. Bản ghi phải bao gồm phiên startTime, endTime và danh sách các đối tượng SleepSessionRecord.Stage được ghi lại trong phiên, vì SleepSessionRecord yêu cầu endTime phải sau startTime.
Cách ghi dữ liệu về một phiên giấc ngủ:
- Tạo một mã nhận dạng riêng biệt cho bản ghi khách hàng.
- Khi người dùng thức dậy hoặc khi quá trình theo dõi giấc ngủ dừng lại, hãy thu thập tất cả các giai đoạn ngủ và tạo một
SleepSessionRecord. - Chèn bản ghi bằng
insertRecords.
Ví dụ:
val clientRecordId = UUID.randomUUID().toString()
val sessionStartTime = LocalDateTime.of(2023, 10, 30, 22, 0).toInstant(ZoneOffset.UTC)
val sessionEndTime = LocalDateTime.of(2023, 10, 31, 7, 0).toInstant(ZoneOffset.UTC)
val stages = mutableListOf<SleepSessionRecord.Stage>()
// Add recorded stages, for example:
stages.add(SleepSessionRecord.Stage(
startTime = sessionStartTime.plusSeconds(3600),
endTime = sessionStartTime.plusSeconds(7200),
stage = SleepSessionRecord.STAGE_TYPE_LIGHT)
)
stages.add(SleepSessionRecord.Stage(
startTime = sessionStartTime.plusSeconds(7200),
endTime = sessionStartTime.plusSeconds(10800),
stage = SleepSessionRecord.STAGE_TYPE_DEEP)
)
// ... other stages
val session = SleepSessionRecord(
startTime = sessionStartTime,
startZoneOffset = ZoneOffset.UTC,
endTime = sessionEndTime,
endZoneOffset = ZoneOffset.UTC,
stages = stages,
metadata = Metadata(clientRecordId = clientRecordId)
)
healthConnectClient.insertRecords(listOf(session))
Đọc dữ liệu giấc ngủ
Các ứng dụng có thể đọc các phiên ngủ và dữ liệu liên quan để tóm tắt hoạt động, cung cấp thông tin chi tiết về sức khoẻ hoặc đồng bộ hoá dữ liệu với một máy chủ bên ngoài. Ví dụ: bạn có thể đọc một SleepSessionRecord rồi truy vấn HeartRateRecord đã xảy ra trong cùng khoảng thời gian đó.
Phiên đọc có dữ liệu liên kết
Bạn có thể đọc các phiên ngủ bằng cách sử dụng ReadRecordsRequest với SleepSessionRecord làm loại bản ghi, được lọc theo một khoảng thời gian. Để đọc dữ liệu được liên kết cho một giấc ngủ nhất định, hãy đưa ra yêu cầu thứ hai cho loại dữ liệu đã chọn, chẳng hạn như HeartRateRecord – lọc theo startTime và endTime của giấc ngủ.
Ví dụ sau đây cho biết cách đọc các phiên giấc ngủ có dữ liệu tần số tim liên quan trong một phạm vi thời gian nhất định:
suspend fun readSleepSessionsWithAssociatedData(
healthConnectClient: HealthConnectClient,
startTime: Instant,
endTime: Instant
) {
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = SleepSessionRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
for (sleepRecord in response.records) {
// Process each session
val stages = sleepRecord.stages
val notes = sleepRecord.notes
// To read specific granular data (like heart rate) that occurred during
// this session, use the session's startTime and endTime to filter
// the request for that data type.
val hrResponse = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = HeartRateRecord::class,
timeRangeFilter = TimeRangeFilter.between(
sleepRecord.startTime,
sleepRecord.endTime
)
)
)
for (heartRateRecord in hrResponse.records) {
for (sample in heartRateRecord.samples) {
val bpm = sample.beatsPerMinute
}
}
}
}
Các phương pháp hay nhất
Hãy làm theo các nguyên tắc này để cải thiện độ tin cậy của dữ liệu và trải nghiệm người dùng:
- Tần suất ghi
- Theo dõi chủ động(Nền trước): Để theo dõi giấc ngủ chủ động, hãy ghi dữ liệu khi có dữ liệu hoặc trong khoảng thời gian tối đa là 15 phút.
- Đồng bộ hoá ở chế độ nền: Sử dụng
WorkManagercho các lượt ghi bị hoãn. Đặt khoảng thời gian là 15 phút để cân bằng giữa dữ liệu theo thời gian thực và hiệu suất pin. - Xử lý hàng loạt: Không ghi từng sự kiện cảm biến riêng lẻ. Phân đoạn các yêu cầu của bạn. Health Connect xử lý tối đa 1.000 bản ghi cho mỗi yêu cầu ghi.
- Giữ mã nhận dạng phiên ổn định và duy nhất: Sử dụng các giá trị nhận dạng nhất quán cho các phiên của bạn. Nếu một phiên được chỉnh sửa hoặc cập nhật, việc sử dụng cùng một mã nhận dạng sẽ ngăn phiên đó bị coi là một giấc ngủ mới, riêng biệt.
- Sử dụng tính năng xử lý hàng loạt cho các loại dữ liệu: Để giảm chi phí đầu vào/đầu ra và duy trì thời lượng pin, hãy nhóm các điểm dữ liệu của bạn thành một lệnh gọi
insertRecordsduy nhất thay vì ghi từng điểm riêng lẻ. Tránh ghi dữ liệu trùng lặp: Sử dụng mã ứng dụng Khi tạo bản ghi, hãy đặt một
metadata.clientRecordId. Health Connect sử dụng thông tin này để xác định các bản ghi riêng biệt. Nếu bạn cố gắng ghi một bản ghi cóclientRecordIdđã tồn tại, Health Connect sẽ bỏ qua bản ghi trùng lặp hoặc cập nhật bản ghi hiện có thay vì tạo bản ghi mới. Đặtmetadata.clientRecordIdlà cách hiệu quả nhất để ngăn chặn các bản sao trong quá trình đồng bộ hoá lại hoặc cài đặt lại ứng dụng.val record = RespiratoryRateRecord( rate = 16.0, time = time, zoneOffset = ZoneOffset.UTC, metadata = Metadata( // Use a unique ID from your own database clientRecordId = "respiratory_rate_20231030_1" ) )Kiểm tra dữ liệu hiện có: Trước khi đồng bộ hoá, hãy truy vấn phạm vi thời gian để xem có bản ghi nào từ ứng dụng của bạn đã tồn tại hay chưa.
Đảm bảo dấu thời gian không trùng lặp: Xác minh rằng một phiên mới không bắt đầu trước khi phiên trước kết thúc. Các phiên tập luyện chồng chéo có thể gây ra xung đột trong bảng điều khiển và các phép tính tóm tắt về hoạt động thể dục.
Đưa ra lý do rõ ràng cho quyền: Sử dụng quy trình
Permission.createIntentđể giải thích lý do ứng dụng của bạn cần quyền truy cập vào dữ liệu sức khoẻ, chẳng hạn như "Để phân tích giấc ngủ của bạn".Kiểm thử các phiên hoạt động kéo dài: Theo dõi mức tiêu thụ pin trong các phiên hoạt động kéo dài vài giờ để xác minh rằng khoảng thời gian theo lô và mức sử dụng cảm biến không làm hao pin thiết bị.
Điều chỉnh dấu thời gian theo tốc độ của cảm biến: Điều chỉnh dấu thời gian của bản ghi theo tần suất thực tế của cảm biến để duy trì độ trung thực cao của dữ liệu.
Thử nghiệm
Để xác minh tính chính xác của dữ liệu và trải nghiệm người dùng chất lượng cao, hãy làm theo các chiến lược kiểm thử này và tham khảo tài liệu chính thức về Kiểm thử các trường hợp sử dụng hàng đầu.
Công cụ xác minh
- Hộp công cụ Health Connect: Sử dụng ứng dụng bổ trợ này để kiểm tra các bản ghi theo cách thủ công, xoá dữ liệu kiểm thử và mô phỏng các thay đổi đối với cơ sở dữ liệu. Đây là cách tốt nhất để xác minh rằng các bản ghi của bạn đang được lưu trữ đúng cách.
- Kiểm thử đơn vị bằng
FakeHealthConnectClient: Sử dụng thư viện kiểm thử để xác minh cách ứng dụng của bạn xử lý các trường hợp đặc biệt, chẳng hạn như thu hồi quyền hoặc ngoại lệ API mà không cần thiết bị thực.
Danh sách kiểm tra chất lượng
Kiến trúc điển hình
Việc triển khai tính năng theo dõi giấc ngủ thường bao gồm:
| Thành phần | Quản lý |
|---|---|
| Bộ điều khiển phiên | Trạng thái phiên Bộ hẹn giờ Logic phân lô Bộ điều khiển kiểu dữ liệu Thu thập dữ liệu |
| Lớp kho lưu trữ (bao gồm các thao tác trên Health Connect): | Chèn phiên Chèn loại dữ liệu Chèn các giai đoạn ngủ Đọc bản tóm tắt phiên |
| Lớp giao diện người dùng (Màn hình): | Thời lượng Loại dữ liệu trực tiếp Hình ảnh trực quan về giai đoạn ngủ |
Khắc phục sự cố
| Dấu hiệu | Nguyên nhân có thể gây ra lỗi | Độ phân giải |
|---|---|---|
| Thiếu các loại dữ liệu (Ví dụ: Nhịp tim) | Thiếu quyền ghi hoặc bộ lọc thời gian không chính xác. | Kiểm tra để đảm bảo bạn đã yêu cầu và người dùng đã cấp quyền cho loại dữ liệu cụ thể. Xác minh rằng ReadRecordsRequest của bạn sử dụng TimeRangeFilter khớp với phiên. Xem phần Quyền. |
| Không ghi được phiên | Dấu thời gian trùng lặp. | Health Connect có thể từ chối những bản ghi trùng lặp với dữ liệu hiện có của cùng một ứng dụng. Hãy xác thực rằng startTime của một phiên mới diễn ra sau endTime của phiên trước đó. |
| Không có dữ liệu cảm biến được ghi lại trong khi ngủ | Dịch vụ trên nền trước đã bị vô hiệu hoá hoặc không hoạt động. | Để thu thập dữ liệu cảm biến qua đêm khi màn hình tắt, bạn có thể sử dụng Dịch vụ trên nền trước với foregroundServiceType="health". |
| Các bản ghi trùng lặp xuất hiện | Thiếu clientRecordId |
Chỉ định một clientRecordId duy nhất trong Metadata của mỗi bản ghi. Điều này cho phép Health Connect thực hiện việc loại bỏ dữ liệu trùng lặp nếu cùng một dữ liệu được ghi hai lần trong quá trình đồng bộ hoá lại. Xem Các phương pháp hay nhất. |
Các bước gỡ lỗi thường gặp
- Kiểm tra trạng thái Quyền: Luôn gọi
getPermissionStatus()trước khi thử thực hiện thao tác đọc hoặc ghi. Người dùng có thể thu hồi quyền trong phần cài đặt hệ thống bất cứ lúc nào. - Xác minh chế độ thực thi: Nếu ứng dụng của bạn không thu thập dữ liệu ở chế độ nền, hãy xác minh rằng bạn đã khai báo các quyền chính xác trong
AndroidManifest.xmlvà người dùng chưa đặt ứng dụng ở chế độ "Hạn chế sử dụng pin".