Ghi dữ liệu

Hướng dẫn này tương thích với Health Connect phiên bản 1.1.0-alpha12 trở lên.

Hướng dẫn này trình bày quy trình ghi hoặc cập nhật dữ liệu trong Health Connect.

Xử lý giá trị bằng 0

Một số loại dữ liệu như số bước, quãng đường hoặc lượng calo có thể có giá trị là 0. Chỉ ghi giá trị bằng 0 khi giá trị này phản ánh đúng trạng thái không hoạt động trong khi người dùng đeo thiết bị. Đừng ghi giá trị bằng 0 nếu người dùng không đeo thiết bị, thiếu dữ liệu hoặc thiết bị hết pin. Trong những trường hợp như vậy, hãy bỏ qua bản ghi để tránh dữ liệu gây hiểu lầm.

Thiết lập cấu trúc dữ liệu

Trước khi ghi dữ liệu, chúng ta cần thiết lập bản ghi. Trong số hơn 50 loại dữ liệu, mỗi loại đều có cấu trúc riêng tương ứng. Vui lòng xem Tài liệu tham khảo về Jetpack để biết thêm thông tin chi tiết về các loại dữ liệu có thể dùng.

Bản ghi cơ bản

Loại dữ liệu về Số bước trong Health Connect ghi lại số bước người dùng đi được giữa các lần đọc. Số bước chính là cách đo lường phổ biến trên các nền tảng về sức khoẻ, hoạt động thể chất và sức khoẻ tinh thần.

Ví dụ sau đây cho thấy cách thiết lập dữ liệu số bước:

val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(startTime)
val stepsRecord = StepsRecord(
    count = 120,
    startTime = startTime,
    endTime = endTime,
    startZoneOffset = zoneOffset,
    endZoneOffset = zoneOffset,
    metadata = Metadata.autoRecorded(
        device = Device(type = Device.TYPE_WATCH)
    )
)
healthConnectClient.insertRecords(listOf(stepsRecord))

Bản ghi có đơn vị đo lường

Health Connect có thể lưu trữ các giá trị kèm theo đơn vị đo lường để mang lại sự chính xác. Ví dụ: loại dữ liệu Dinh dưỡng rất rộng lớn và toàn diện. Loại dữ liệu này bao gồm nhiều trường không bắt buộc về dinh dưỡng, từ tổng lượng carbohydrate đến vitamin. Mỗi điểm dữ liệu biểu thị những chất dinh dưỡng có thể tiêu thụ trong bữa ăn hoặc món ăn.

Trong loại dữ liệu này, tất cả các chất dinh dưỡng được biểu thị bằng đơn vị Khối lượng, còn energy được biểu thị bằng đơn vị Năng lượng.

Ví dụ sau đây cho biết cách thiết lập dữ liệu dinh dưỡng khi người dùng ăn một quả chuối:

val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofMinutes(1))

val banana = NutritionRecord(
    name = "banana",
    energy = 105.0.kilocalories,
    dietaryFiber = 3.1.grams,
    potassium = 0.422.grams,
    totalCarbohydrate = 27.0.grams,
    totalFat = 0.4.grams,
    saturatedFat = 0.1.grams,
    sodium = 0.001.grams,
    sugar = 14.0.grams,
    vitaminB6 = 0.0005.grams,
    vitaminC = 0.0103.grams,
    startTime = startTime,
    endTime = endTime,
    startZoneOffset = ZoneOffset.UTC,
    endZoneOffset = ZoneOffset.UTC,
    metadata = Metadata.activelyRecorded(
        device = Device(type = Device.TYPE_PHONE)
    )
)

Bản ghi có dữ liệu theo chuỗi

Health Connect có thể lưu trữ danh sách dữ liệu theo chuỗi. Ví dụ: loại dữ liệu Nhịp tim ghi lại một loạt mẫu nhịp tim được phát hiện giữa các lần đọc.

Trong loại dữ liệu này, tham số samples được biểu thị bằng một danh sách mẫu Nhịp tim. Mỗi mẫu đều chứa một giá trị beatsPerMinute và một giá trị time.

Ví dụ sau đây trình bày cách thiết lập dữ liệu theo chuỗi về nhịp tim:

val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofMinutes(5))

val heartRateRecord = HeartRateRecord(
    startTime = startTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = endTime,
    endZoneOffset = ZoneOffset.UTC,
    // records 10 arbitrary data, to replace with actual data
    samples = List(10) { index ->
        HeartRateRecord.Sample(
            time = startTime + Duration.ofSeconds(index.toLong()),
            beatsPerMinute = 100 + index.toLong(),
        )
    },
    metadata = Metadata.activelyRecorded(
        device = Device(type = Device.TYPE_WATCH)
    ))

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.

val permissions =
    setOf(
        HealthPermission.getReadPermission(HeartRateRecord::class),
        HealthPermission.getWritePermission(HeartRateRecord::class),
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::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.
val permissions = setOf(
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::class),
        HealthPermission.getReadPermission(HeartRateRecord::class),
        HealthPermission.getWritePermission(HeartRateRecord::class)
    )

val requestPermissionsLauncher = rememberLauncherForActivityResult(
    contract = PermissionController.createRequestPermissionResultContract()
) { grantedPermissions ->
    if (grantedPermissions.containsAll(permissions)) {
        coroutineScope.launch { snackbarHostState.showSnackbar("Permissions granted!") }
    } else {
        coroutineScope.launch { snackbarHostState.showSnackbar("Permissions denied.") }
    }
}
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 lần trước khi sử dụng và xử lý các trường hợp mất quyền.

Ghi dữ liệu

Ghi dữ liệu là một trong những quy trình công việc phổ biến trong Health Connect. Để thêm bản ghi, hãy dùng insertRecords.

Ví dụ sau đây cho thấy cách ghi dữ liệu chèn số bước:

val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(startTime)
val stepsRecord = StepsRecord(
    count = 120,
    startTime = startTime,
    endTime = endTime,
    startZoneOffset = zoneOffset,
    endZoneOffset = zoneOffset,
    metadata = Metadata.autoRecorded(
        device = Device(type = Device.TYPE_WATCH)
    )
)
healthConnectClient.insertRecords(listOf(stepsRecord))

Cập nhật dữ liệu

Nếu cần thay đổi một hoặc nhiều bản ghi, đặc biệt là khi cần đồng bộ hoá kho dữ liệu ứng dụng của bạn với dữ liệu từ Health Connect, bạn có thể cập nhật dữ liệu của mình. Có 2 cách cập nhật dữ liệu hiện có, tuỳ thuộc vào giá trị nhận dạng dùng để tìm bản ghi.

Siêu dữ liệu

Trước tiên, bạn cần kiểm tra lớp Metadata vì điều này là cần thiết khi cập nhật dữ liệu. Khi được tạo, mỗi Record trong Health Connect có một trường metadata. Các thuộc tính sau có liên quan đến quá trình đồng bộ hoá:

Thuộc tính Nội dung mô tả
id Mỗi Record trong Health Connect đều có một giá trị id duy nhất.
Health Connect sẽ tự động điền giá trị nàykhi chèn một bản ghi mới.
lastModifiedTime Mỗi Record cũng có thông tin về lần sửa đổi bản ghi gần đây nhất.
Health Connect sẽ tự động điền thông tin này.
clientRecordId Mỗi Record có thể có một mã nhận dạng duy nhất liên kết với bản ghi đó để làm tệp đối chiếu trong kho dữ liệu ứng dụng của bạn.
Ứng dụng của bạn cung cấp giá trị này.
clientRecordVersion Khi một bản ghi có clientRecordId, bạn có thể dùng clientRecordVersion để dữ liệu luôn đồng bộ với phiên bản trong kho dữ liệu ứng dụng của bạn.
Ứng dụng của bạn cung cấp giá trị này.

Cập nhật sau khi đọc theo phạm vi thời gian

Để cập nhật dữ liệu, trước tiên, hãy chuẩn bị các bản ghi cần thiết. Thực hiện mọi thay đổi đối với bản ghi, nếu cần. Sau đó, hãy gọi updateRecords để thực hiện các thay đổi.

Ví dụ sau đây cho thấy cách cập nhật dữ liệu. Vì mục đích này, mỗi bản ghi sẽ được điều chỉnh giá trị chênh lệch múi giờ thành PST.

suspend fun updateSteps(
    healthConnectClient: HealthConnectClient,
    prevRecordStartTime: Instant,
    prevRecordEndTime: Instant
) {
    try {
        val request = healthConnectClient.readRecords(
            ReadRecordsRequest(
                recordType = StepsRecord::class, timeRangeFilter = TimeRangeFilter.between(
                    prevRecordStartTime,
                    prevRecordEndTime
                )
            )
        )

        val newStepsRecords = arrayListOf<StepsRecord>()
        for (record in request.records) {
            // Adjusted both offset values to reflect changes
            val sr = StepsRecord(
                count = record.count,
                startTime = record.startTime,
                startZoneOffset = record.startTime.atZone(ZoneId.of("PST")).offset,
                endTime = record.endTime,
                endZoneOffset = record.endTime.atZone(ZoneId.of("PST")).offset,
                metadata = record.metadata
            )
            newStepsRecords.add(sr)
        }

        healthConnectClient.updateRecords(newStepsRecords)
    } catch (e: Exception) {
        // Run error handling here
    }
}

Cập nhật và chèn thông qua mã bản ghi máy khách

Nếu đang dùng các giá trị không bắt buộc là Mã bản ghi máy khách và Phiên bản bản ghi máy khách, bạn nên sử dụng insertRecords thay vì updateRecords.

Hàm insertRecords có khả năng cập nhật và chèn dữ liệu. Nếu tồn tại dữ liệu trong Health Connect dựa trên bộ Mã bản ghi máy khách đã cho, thì dữ liệu đó sẽ bị ghi đè. Nếu không, dữ liệu sẽ được ghi dưới dạng dữ liệu mới. Trường hợp này rất có ích bất cứ khi nào bạn cần đồng bộ hoá dữ liệu từ kho dữ liệu ứng dụng của mình với Health Connect.

Ví dụ sau đây cho thấy cách cập nhật và chèn dữ liệu lấy từ kho dữ liệu ứng dụng:

 fun pullStepsFromDatastore(startTime: Instant, endTime: Instant) : ArrayList<StepsRecord> {
    val appStepsRecords = arrayListOf<StepsRecord>()
    // Pull data from app datastore
    // ...
    // Make changes to data if necessary
    // ...
    // Store data in appStepsRecords
    // ...
    var sr = StepsRecord(
        metadata = Metadata.activelyRecorded(
            clientRecordId = "Your client record ID",
            clientRecordVersion = 0L,
            device = Device(type = Device.TYPE_WATCH)
        ),
        startTime = startTime,
        startZoneOffset = startTime.atZone(ZoneId.of("PST")).offset,
        endTime = endTime,
        endZoneOffset = endTime.atZone(ZoneId.of("PST")).offset,
        count = 120
    )
    appStepsRecords.add(sr)
    // ...
    return appStepsRecords
}

suspend fun upsertSteps(
    healthConnectClient: HealthConnectClient,
    newStepsRecords: ArrayList<StepsRecord>
) {
    try {
        healthConnectClient.insertRecords(newStepsRecords)
    } catch (e: Exception) {
        // Run error handling here
    }
}

Sau đó, bạn có thể gọi các hàm này trong luồng chính.

upsertSteps(healthConnectClient, pullStepsFromDatastore(
    startTime = startTime,
    endTime = endTime
))

Kiểm tra giá trị trong Phiên bản bản ghi máy khách

Nếu quá trình cập nhật và chèn dữ liệu bao gồm cả Phiên bản bản ghi máy khách, thì Health Connect sẽ thực hiện các phép kiểm tra so sánh trong giá trị clientRecordVersion. Nếu phiên bản của dữ liệu được chèn cao hơn phiên bản của dữ liệu hiện có, thì quá trình cập nhật và chèn dữ liệu sẽ xảy ra. Nếu không, quá trình này sẽ bỏ qua sự thay đổi và giữ nguyên giá trị.

Để đưa quá trình lập phiên bản vào dữ liệu, bạn cần cung cấp cho Metadata.clientRecordVersion giá trị Long dựa trên logic lập phiên bản.

val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofMinutes(15))

val stepsRecord = StepsRecord(
    count = 100L,
    startTime = startTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = endTime,
    endZoneOffset = ZoneOffset.UTC,
    metadata = Metadata.activelyRecorded(
        clientRecordId = "Your supplied record ID",
        clientRecordVersion = 0L, // Your supplied record version
        device = Device(type = Device.TYPE_WATCH)
    )
)

Quá trình cập nhật và chèn dữ liệu sẽ không tự động tăng version mỗi khi có các thay đổi để tránh mọi trường hợp ngoài dự kiến của việc ghi đè dữ liệu. Do đó, bạn phải cung cấp giá trị cao hơn theo cách thủ công.

Hướng dẫn chung

Ứng dụng của bạn phải ghi tất cả dữ liệu được hỗ trợ của bên thứ nhất. Nếu muốn, bạn có thể chọn cho phép ứng dụng ghi dữ liệu thu được từ các nguồn bên thứ ba. Tuy nhiên, nếu ứng dụng của bạn đã đọc dữ liệu từ Health Connect, thì dữ liệu đó không được ghi lại vào Health Connect.

Khi ghi dữ liệu đã được nhập hoặc lấy từ một nguồn khác, bạn phải ghi nhận chính xác nguồn gốc và siêu dữ liệu của thiết bị nguồn. Để làm việc này, bạn phải cung cấp siêu dữ liệu sau đây cho mỗi bản ghi văn bản:

  • recordingMethod: Đối với dữ liệu được ghi lại tự động hoặc thủ công, chúng tôi muốn phương thức ghi lại được cập nhật để phản ánh loại hoạt động đã được ghi lại:
    • RECORDING_METHOD_AUTOMATICALLY_RECORDED: Nếu dữ liệu được ghi lại tự động, ví dụ: vòng đeo tay thể dục tự động phát hiện người dùng đã chạy bộ.
    • RECORDING_METHOD_ACTIVELY_RECORDED: Nếu người dùng bắt đầu một hoạt động mới, chẳng hạn như đạp xe trên thiết bị đeo.
    • RECORDING_METHOD_MANUAL_ENTRY: Nếu người dùng nhập dữ liệu theo cách thủ công.
  • device.type: Bạn phải chỉ định một loại thiết bị trong số các loại Device được hỗ trợ.
  • device.manufacturer: Nhà sản xuất thiết bị, ví dụ: "Fitbit".
  • device.model: Kiểu thiết bị, ví dụ: "Charge 3".
  • device.udi: (Không bắt buộc) Phần Giá trị nhận dạng thiết bị (DI) của Giá trị nhận dạng thiết bị duy nhất (UDI) của thiết bị y tế. Để biết thông tin chi tiết về các nguyên tắc bắt buộc về quyền và quyền riêng tư, hãy tham khảo hướng dẫn về siêu dữ liệu.

Việc đặt siêu dữ liệu chính xác là rất quan trọng để đảm bảo tính minh bạch của dữ liệu và giúp người dùng hiểu được nguồn gốc thông tin sức khoẻ của họ. Để biết thông tin chi tiết đầy đủ, hãy tham khảo hướng dẫn về siêu dữ liệu của Health Connect.

Nếu dữ liệu trong ứng dụng của bạn được nhập từ một ứng dụng khác, thì ứng dụng đó có trách nhiệm ghi dữ liệu tương ứng vào Health Connect.

Bạn cũng nên triển khai logic giúp xử lý các trường hợp ngoại lệ của hoạt động ghi, chẳng hạn như dữ liệu nằm ngoài ranh giới hoặc lỗi hệ thống nội bộ. Bạn có thể áp dụng chiến lược thời gian đợi và chiến lược thử lại cho cơ chế lên lịch công việc. Nếu như cuối cùng không ghi được dữ liệu vào Health Connect, hãy đảm bảo rằng ứng dụng có thể vượt qua điểm xuất đó. Đừng quên ghi nhật ký và báo cáo lỗi để hỗ trợ hoạt động chẩn đoán.

Khi theo dõi dữ liệu, tuỳ vào cách ứng dụng của bạn ghi dữ liệu, bạn có thể làm theo một vài gợi ý sau đây.

Xử lý múi giờ

Khi ghi lại các bản ghi dựa trên thời gian, hãy tránh đặt độ lệch thành zoneOffset.UTC theo mặc định vì điều này có thể dẫn đến dấu thời gian không chính xác khi người dùng ở các múi giờ khác. Thay vào đó, hãy tính độ lệch dựa trên vị trí thực tế của thiết bị. Bạn có thể truy xuất múi giờ của thiết bị bằng cách sử dụng ZoneId.systemDefault().

val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofDays(1))
val stepsRecords = mutableListOf<StepsRecord>()
var sampleTime = startTime
val minutesBetweenSamples = 15L
while (sampleTime < endTime) {
    // Get the default ZoneId then convert it to an offset
    val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(sampleTime)
    stepsRecords += StepsRecord(
        startTime = sampleTime.minus(Duration.ofMinutes(minutesBetweenSamples)),
        startZoneOffset = zoneOffset,
        endTime = sampleTime,
        endZoneOffset = zoneOffset,
        count = Random.nextLong(1, 100),
        metadata = Metadata.activelyRecorded(device = Device(type = Device.TYPE_WATCH)),
    )
    sampleTime = sampleTime.plus(Duration.ofMinutes(minutesBetweenSamples))
}
healthConnectClient.insertRecords(
    stepsRecords
)

Hãy xem tài liệu về ZoneId để biết thêm thông tin chi tiết.

Tần suất và mức độ chi tiết của hoạt động ghi dữ liệu

Khi ghi dữ liệu vào Health Connect, hãy sử dụng độ phân giải phù hợp. Việc sử dụng độ phân giải phù hợp giúp giảm tải cho bộ nhớ, trong khi vẫn duy trì dữ liệu nhất quán và chính xác. Độ phân giải dữ liệu bao gồm hai yếu tố:

  • Tần suất ghi: Tần suất ứng dụng ghi dữ liệu mới vào Health Connect.
    • Ghi dữ liệu thường xuyên nhất có thể khi có dữ liệu mới, đồng thời lưu ý đến hiệu suất của thiết bị.
    • Để tránh ảnh hưởng tiêu cực đến thời lượng pin và các khía cạnh hiệu suất khác, khoảng thời gian tối đa giữa các lần ghi phải là 15 phút.
  • Độ chi tiết của dữ liệu được ghi: Tần suất lấy mẫu dữ liệu.
    • Ví dụ: ghi mẫu tần số tim sau mỗi 5 giây.
    • Không phải mọi loại dữ liệu đều yêu cầu cùng một tốc độ lấy mẫu. Việc cập nhật dữ liệu số bước mỗi giây mang lại rất ít lợi ích, thay vào đó hãy dùng tần suất thấp hơn, chẳng hạn như 60 giây/lần.
    • Tốc độ lấy mẫu càng cao thì người dùng càng có cái nhìn chi tiết hơn về dữ liệu sức khoẻ và dữ liệu thể chất của họ. Tốc độ lấy mẫu nên cân bằng giữa mức độ chi tiết và hiệu suất.

Nguyên tắc bổ sung

Hãy làm theo các nguyên tắc sau khi ghi dữ liệu:

  • Trong mỗi lần đồng bộ hoá, chỉ ghi dữ liệu mới và dữ liệu được cập nhật kể từ lần đồng bộ hoá gần nhất.
  • Phân đoạn các yêu cầu lên tối đa 1.000 bản ghi cho mỗi yêu cầu ghi.
  • Hạn chế để các tác vụ chỉ chạy khi thiết bị ở trạng thái rảnh và không bị yếu pin.
  • Đối với các tác vụ ở chế độ nền, hãy sử dụng WorkManager để lên lịch cho các tác vụ định kỳ, với khoảng thời gian tối đa là 15 phút.

Mã sau đây sử dụng WorkManager để lên lịch các tác vụ định kỳ ở chế độ nền, với khoảng thời gian tối đa là 15 phút và khoảng thời gian linh hoạt là 5 phút. Cấu hình này được đặt bằng lớp PeriodicWorkRequest.Builder.

val constraints = Constraints.Builder()
    .requiresBatteryNotLow()
    .requiresDeviceIdle(true)
    .build()

val writeDataWork = PeriodicWorkRequestBuilder<WriteDataToHealthConnectWorker>(
        15,
        TimeUnit.MINUTES,
        5,
        TimeUnit.MINUTES
    )
    .setConstraints(constraints)
    .build()

Theo dõi chủ động

Hình thức này bao gồm những ứng dụng tiến hành hoạt động theo dõi dựa trên sự kiện (như tập thể dục và ngủ) hoặc dữ liệu do người dùng nhập thủ công (chẳng hạn như dinh dưỡng). Những bản ghi này được tạo khi ứng dụng chạy ở nền trước hoặc trong các sự kiện hiếm gặp khi ứng dụng được dùng vài lần trong một ngày.

Xác minh rằng ứng dụng của bạn không sử dụng Health Connect trong toàn bộ thời gian diễn ra sự kiện.

Dữ liệu phải được ghi vào Health Connect theo một trong 2 cách:

  • Đồng bộ hoá dữ liệu với Health Connect sau khi sự kiện hoàn thành. Ví dụ: đồng bộ hoá dữ liệu khi người dùng kết thúc một phiên tập thể dục được theo dõi.
  • Lên lịch cho tác vụ một lần bằng WorkManager để đồng bộ hoá dữ liệu vào lúc khác.

Các phương pháp hay nhất về mức độ chi tiết và tần suất ghi

Khi ghi dữ liệu vào Health Connect, hãy sử dụng độ phân giải phù hợp. Việc sử dụng độ phân giải phù hợp giúp giảm tải cho bộ nhớ, trong khi vẫn duy trì dữ liệu nhất quán và chính xác. Độ phân giải dữ liệu bao gồm 2 yếu tố:

  1. Tần suất ghi: tần suất ứng dụng của bạn đẩy dữ liệu mới vào Health Connect. Ghi dữ liệu thường xuyên nhất có thể khi có dữ liệu mới, đồng thời lưu ý đến hiệu suất của thiết bị. Để tránh ảnh hưởng tiêu cực đến thời lượng pin và các khía cạnh hiệu suất khác, khoảng thời gian tối đa giữa các lần ghi phải là 15 phút.

  2. Độ chi tiết của dữ liệu được ghi: tần suất lấy mẫu dữ liệu được đẩy vào. Ví dụ: ghi lại mẫu tần số tim sau mỗi 5 giây. Không phải mọi loại dữ liệu đều yêu cầu cùng một tốc độ lấy mẫu. Việc cập nhật dữ liệu số bước mỗi giây mang lại rất ít lợi ích, thay vào đó hãy dùng tần suất thấp hơn, chẳng hạn như 60 giây/lần. Tuy nhiên, tốc độ lấy mẫu càng cao thì người dùng càng có cái nhìn chi tiết hơn về dữ liệu sức khoẻ và hoạt động thể dục của họ. Tốc độ lấy mẫu nên cân bằng giữa mức độ chi tiết và hiệu suất.

Cấu trúc bản ghi cho dữ liệu theo chuỗi

Đối với các loại dữ liệu sử dụng một loạt mẫu, chẳng hạn như HeartRateRecord, bạn cần phải cấu trúc bản ghi của mình một cách chính xác. Thay vì tạo một bản ghi duy nhất kéo dài cả ngày và được cập nhật liên tục, bạn nên tạo nhiều bản ghi nhỏ hơn, mỗi bản ghi đại diện cho một khoảng thời gian cụ thể.

Ví dụ: đối với dữ liệu tần số tim, bạn nên tạo một HeartRateRecord mới cho mỗi phút. Mỗi bản ghi sẽ có thời gian bắt đầu và thời gian kết thúc kéo dài trong phút đó, đồng thời chứa tất cả các mẫu tần số tim được ghi lại trong phút đó.

Trong quá trình đồng bộ hoá thường xuyên với Health Connect (ví dụ: 15 phút một lần), ứng dụng của bạn sẽ ghi tất cả bản ghi một phút đã được tạo kể từ lần đồng bộ hoá trước đó. Điều này giúp giữ cho các bản ghi ở kích thước có thể quản lý được và cải thiện hiệu suất truy vấn cũng như xử lý dữ liệu.

Ví dụ sau đây cho thấy cách tạo HeartRateRecord cho một phút, chứa nhiều mẫu:

val startTime = Instant.now().truncatedTo(ChronoUnit.MINUTES)
val endTime = startTime.plus(Duration.ofMinutes(1))

val heartRateRecord = HeartRateRecord(
    startTime = startTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = endTime,
    endZoneOffset = ZoneOffset.UTC,
    // Create a new record every minute, containing a list of samples.
    samples = listOf(
        HeartRateRecord.Sample(
            time = startTime + Duration.ofSeconds(15),
            beatsPerMinute = 80,
        ),
        HeartRateRecord.Sample(
            time = startTime + Duration.ofSeconds(30),
            beatsPerMinute = 82,
        ),
        HeartRateRecord.Sample(
            time = startTime + Duration.ofSeconds(45),
            beatsPerMinute = 85,
        )
    ),
    metadata = Metadata.activelyRecorded(
        device = Device(type = Device.TYPE_WATCH)
    ))

Ghi dữ liệu được theo dõi trong suốt cả ngày

Đối với dữ liệu được thu thập liên tục, chẳng hạn như số bước, ứng dụng của bạn nên ghi vào Health Connect thường xuyên nhất có thể khi có dữ liệu mới. Để tránh ảnh hưởng tiêu cực đến thời lượng pin và các khía cạnh hiệu suất khác, khoảng thời gian tối đa giữa các lần ghi phải là 15 phút.

Bảng 1: Hướng dẫn ghi dữ liệu

Kiểu dữ liệu

Đơn vị

Dự kiến

Ví dụ

Các bước

bước

Mỗi phút

23:14 – 23:15 – 5 bước

23:16 – 23:17 – 22 bước

23:17 – 23:18 – 8 bước

StepsCadence

bước/phút

Mỗi phút

23:14 – 23:15 – 5 bước/phút

23:16 – 23:17 – 22 bước/phút

23:17 – 23:18 – 8 bước/phút

Số lần đẩy xe lăn

lượt đẩy

Mỗi phút

23:14 – 23:15 – 5 lần đẩy

23:16 – 23:17 – 22 lần đẩy

23:17 – 23:18 – 8 lần đẩy

ActiveCaloriesBurned

Calo

15 phút một lần

23:15 – 23:30 – 2 calo

23:30 – 23:45 – 25 calo

23:45 – 00:00 – 5 calo

TotalCaloriesBurned

Calo

15 phút một lần

23:15 – 23:30 – 16 calo

23:30 – 23:45 – 16 calo

23:45 – 00:00 – 16 calo

Khoảng cách

km/phút

Mỗi phút

23:14 – 23:15 – 0,008 km

23:16 – 23:16 – 0,021 km

23:17 – 23:18 – 0,012 km

ElevationGained

m

Mỗi phút

20:36 – 20:37 – 3.048m

20:39 – 20:40 – 3.048 m

23:23 - 23:24 - 9.144m

FloorsClimbed

số tầng

Mỗi phút

23:14 – 23:15 – 5 tầng

23:16 - 23:16 - 22 tầng

23:17 – 23:18 – 8 tầng

HeartRate

nhịp/ph

4 lần/phút

6:11:15 sáng – 55 nhịp/phút

6:11:30 sáng – 56 nhịp/phút

6:11:45 sáng – 56 nhịp/phút

6:12:00 sáng – 55 nhịp/phút

HeartRateVariabilityRmssd

mili giây

Mỗi phút

6:11 sáng – 23 mili giây

RespiratoryRate

nhịp thở/phút

Mỗi phút

23:14 – 23:15 – 60 nhịp thở/phút

23:16 – 23:16 – 62 nhịp thở/phút

23:17 – 23:18 – 64 nhịp thở/phút

OxygenSaturation

%

Mỗi giờ

6:11 - 95.208%

Bạn nên ghi dữ liệu vào Health Connect khi kết thúc phiên tập thể dục hoặc phiên ngủ. Đối với hoạt động theo dõi chủ động, chẳng hạn như tập thể dục và ngủ, hoặc dữ liệu do người dùng nhập thủ công như dinh dưỡng, các bản ghi này được tạo khi ứng dụng chạy ở nền trước hoặc trong các sự kiện hiếm gặp khi ứng dụng được dùng vài lần trong một ngày.

Xác minh rằng ứng dụng của bạn không sử dụng Health Connect trong toàn bộ thời gian diễn ra sự kiện.

Dữ liệu phải được ghi vào Health Connect theo một trong 2 cách:

  • Đồng bộ hoá dữ liệu với Health Connect sau khi sự kiện hoàn thành. Ví dụ: đồng bộ hoá dữ liệu khi người dùng kết thúc một phiên tập thể dục được theo dõi.
  • Dùng WorkManager để lên lịch cho tác vụ một lần rồi đồng bộ hoá dữ liệu sau.

Phiên tập thể dục và phiên ngủ

Tối thiểu, ứng dụng của bạn phải tuân theo hướng dẫn trong cột Dự kiến trong Bảng 2. Nếu có thể, hãy làm theo hướng dẫn trong cột Tốt nhất.

Bảng sau đây cho biết cách ghi dữ liệu trong một bài tập thể dục:

Bảng 2: Hướng dẫn ghi dữ liệu trong một buổi tập thể dục

Kiểu dữ liệu

Đơn vị

Dự kiến

Trân trọng,

Ví dụ

Các bước

bước

Mỗi phút

Mỗi giây

23:14-23:15 – 5 bước

23:16 – 23:17 – 22 bước

23:17 – 23:18 – 8 bước

StepsCadence

bước/phút

Mỗi phút

Mỗi giây

23:14 – 23:15 – 35 bước/phút

23:16 – 23:17 – 37 bước/phút

23:17 – 23:18 – 40 bước/phút

Số lần đẩy xe lăn

lượt đẩy

Mỗi phút

Mỗi giây

23:14-23:15 – 5 lần đẩy

23:16 – 23:17 – 22 lần đẩy

23:17 – 23:18 – 8 lần đẩy

CyclingPedalingCadence

nhịp thở/phút

Mỗi phút

Mỗi giây

23:14 – 23:15 – 65 nhịp thở/phút

23:16 – 23:17 – 70 vòng/phút

23:17 – 23:18 – 68 nhịp thở/phút

Công suất

watt

Mỗi phút

Mỗi giây

23:14-23:15 – 250 watt

23:16 – 23:17 – 255 watt

23:17 – 23:18 – 245 watt

Tốc độ

km/phút

Mỗi phút

Mỗi giây

23:14 – 23:15 – 0,3 km/phút

23:16 – 23:17 – 0,4 km/phút

23:17 – 23:18 -0,4 km/phút

Khoảng cách

km/phút

Mỗi phút

Mỗi giây

23:14 – 23:15 – 0,008 km

23:16 – 23:16 – 0,021 km

23:17 – 23:18 – 0,012 km

ActiveCaloriesBurned

Calo

Mỗi phút

Mỗi giây

23:14-23:15 – 20 calo

23:16 – 23:17 – 20 calo

23:17 – 23:18 – 25 calo

TotalCaloriesBurned

Calo

Mỗi phút

Mỗi giây

23:14-23:15 – 36 calo

23:16 – 23:17 – 36 calo

23:17 – 23:18 – 41 calo

ElevationGained

m

Mỗi phút

Mỗi giây

20:36 – 20:37 – 3.048m

20:39 – 20:40 – 3.048 m

23:23 - 23:24 - 9.144m

ExerciseRoutes

vĩ độ/kinh độ/cao độ

Mỗi 3-5 giây

Mỗi giây

HeartRate

nhịp/ph

4 lần/phút

Mỗi giây

23:14-23:15 – 150 nhịp/phút

Bảng 3 cho thấy cách ghi dữ liệu trong hoặc sau một phiên ngủ:

Bảng 3: Hướng dẫn ghi dữ liệu trong hoặc sau một phiên ngủ

Kiểu dữ liệu

Đơn vị

Mẫu dự kiến

Ví dụ

Các giai đoạn ngủ

giai đoạn

Khoảng thời gian chi tiết cho từng giai đoạn ngủ

23:46 - 23:50 - tỉnh giấc

23:50 – 23:56 – ngủ nông

23:56 – 00:16 – ngủ sâu

RestingHeartRate

nhịp/ph

Một giá trị hằng ngày (nên đo vào buổi sáng sớm)

6:11 – 60 nhịp/phút

OxygenSaturation

%

Một giá trị hằng ngày (nên đo vào buổi sáng sớm)

6:11 - 95.208%

Sự kiện các môn thể thao phối hợp

Phương pháp này sử dụng các loại và cấu trúc dữ liệu hiện có, đồng thời xác minh khả năng tương thích với các phương thức triển khai Health Connect và trình đọc dữ liệu hiện tại. Đây là phương pháp phổ biến mà các nền tảng thể dục áp dụng.

Ngoài ra, các phiên riêng lẻ như bơi lội, đạp xe và chạy không được liên kết sẵn trong Health Connect và trình đọc dữ liệu phải suy luận mối quan hệ giữa các phiên này dựa trên khoảng thời gian gần nhau. Quá trình chuyển đổi giữa các phân đoạn, chẳng hạn như từ bơi sang đạp xe, không được thể hiện rõ ràng.

Ví dụ sau đây cho thấy cách ghi dữ liệu cho một cuộc thi ba môn phối hợp:

val swimStartTime = Instant.parse("2024-08-22T08:00:00Z")
val swimEndTime = Instant.parse("2024-08-22T08:30:00Z")
val bikeStartTime = Instant.parse("2024-08-22T08:40:00Z")
val bikeEndTime = Instant.parse("2024-08-22T09:40:00Z")
val runStartTime = Instant.parse("2024-08-22T09:50:00Z")
val runEndTime = Instant.parse("2024-08-22T10:20:00Z")

val swimSession = ExerciseSessionRecord(
    startTime = swimStartTime,
    endTime = swimEndTime,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_SWIMMING_OPEN_WATER,
    metadata = Metadata.activelyRecorded(
        device = Device(type = Device.TYPE_WATCH)
    ),
    startZoneOffset = null,
    endZoneOffset = null,
)

val bikeSession = ExerciseSessionRecord(
    startTime = bikeStartTime,
    endTime = bikeEndTime,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_BIKING,
    metadata = Metadata.activelyRecorded(
        device = Device(type = Device.TYPE_WATCH)
    ),
    startZoneOffset = null,
    endZoneOffset = null,
)

val runSession = ExerciseSessionRecord(
    startTime = runStartTime,
    endTime = runEndTime,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
    metadata = Metadata.activelyRecorded(
        device = Device(type = Device.TYPE_WATCH)
    ),
    startZoneOffset = null,
    endZoneOffset = null,
)

healthConnectClient.insertRecords(listOf(swimSession, bikeSession, runSession))

Xử lý ngoại lệ

Khi gặp sự cố, Health Connect sẽ gửi những trường hợp ngoại lệ tiêu chuẩn cho các hoạt động CRUD. Ứng dụng của bạn nên nắm bắt và xử lý từng trường hợp ngoại lệ theo cách phù hợp.

Mỗi phương thức trên HealthConnectClient liệt kê các trường hợp ngoại lệ có thể được gửi. Nhìn chung, ứng dụng của bạn phải xử lý các trường hợp ngoại lệ sau:

Bảng 1: Các trường hợp ngoại lệ của Health Connect và các phương pháp hay nhất được đề xuất
Ngoại lệ Mô tả Phương pháp hay nhất được đề xuất
IllegalStateException Một trong các trường hợp sau đã xảy ra:

  • Dịch vụ Health Connect không hoạt động.
  • Yêu cầu không phải là một cấu trúc hợp lệ. Ví dụ: yêu cầu tổng hợp trong các bộ chứa định kỳ trong đó đối tượng Instant được dùng cho timeRangeFilter.

Xử lý các sự cố có thể xảy ra với dữ liệu đầu vào trước khi thực hiện yêu cầu. Bạn nên chỉ định giá trị cho các biến hoặc dùng các biến đó làm tham số trong một hàm tuỳ chỉnh thay vì sử dụng trực tiếp trong các yêu cầu để có thể áp dụng chiến lược xử lý lỗi.
IOException Đã xảy ra sự cố khi đọc và ghi dữ liệu từ ổ đĩa. Để tránh sự cố này, dưới đây là một số đề xuất:

  • Sao lưu mọi hoạt động đầu vào của người dùng.
  • Có thể xử lý mọi sự cố xảy ra trong khi ghi hàng loạt. Ví dụ: hãy đảm bảo quy trình này xử lý được sự cố và thực hiện các thao tác còn lại.
  • Áp dụng các chiến lược thử lại và thời gian đợi để xử lý các sự cố về yêu cầu.

RemoteException Đã xảy ra lỗi trong hoặc khi giao tiếp với dịch vụ cơ bản kết nối với SDK.

Ví dụ: ứng dụng của bạn đang cố gắng xoá một bản ghi có uid cụ thể. Tuy nhiên, trường hợp ngoại lệ sẽ được gửi sau khi ứng dụng phát hiện ra bản ghi không tồn tại trong quá trình kiểm tra dịch vụ cơ bản.
Để tránh sự cố này, dưới đây là một số đề xuất:

  • Thường xuyên đồng bộ hoá giữa kho dữ liệu của ứng dụng và Health Connect.
  • Áp dụng các chiến lược thử lại và thời gian đợi để xử lý các sự cố về yêu cầu.

SecurityException Đã xảy ra sự cố khi các yêu cầu này cần quyền không được cấp. Để tránh tình trạng này, hãy đảm bảo rằng bạn đã khai báo việc sử dụng các loại dữ liệu Health Connect cho ứng dụng đã xuất bản. Ngoài ra, bạn phải khai báo các quyền của Health Connect trong tệp kê khai và trong hoạt động của bạn.