เขียนข้อมูล

คู่มือนี้ใช้ได้กับ Health Connect เวอร์ชัน 1.1.0-alpha12

คู่มือนี้ครอบคลุมกระบวนการเขียนหรืออัปเดตข้อมูลใน Health Connect

จัดการค่า 0

ข้อมูลบางประเภท เช่น จำนวนก้าว ระยะทาง หรือแคลอรี่ อาจมีค่าเป็น 0 ให้เขียนค่าเป็น 0 เฉพาะเมื่อไม่มีการใช้งานจริงในขณะที่ผู้ใช้ สวมอุปกรณ์ อย่าเขียนค่าเป็น 0 หากไม่ได้สวมอุปกรณ์ ข้อมูล ขาดหายไป หรือแบตเตอรี่หมด ในกรณีเช่นนี้ ให้ละเว้นระเบียนเพื่อหลีกเลี่ยงข้อมูลที่ทำให้เข้าใจผิด

ตั้งค่าโครงสร้างข้อมูล

ก่อนที่จะเขียนข้อมูล เราต้องตั้งค่าระเบียนก่อน สำหรับข้อมูลมากกว่า 50 ประเภท แต่ละประเภทจะมีโครงสร้างของตัวเอง ดูรายละเอียดเพิ่มเติมเกี่ยวกับประเภทข้อมูลที่ใช้ได้ในข้อมูลอ้างอิง Jetpack

บันทึกพื้นฐาน

ประเภทข้อมูลจำนวนก้าวใน Health Connect จะบันทึกจำนวนก้าวที่ผู้ใช้เดินระหว่างการอ่าน จำนวนก้าวเป็นหน่วยวัดทั่วไป ในแพลตฟอร์มสุขภาพ การออกกำลังกาย และสุขภาวะ

ตัวอย่างต่อไปนี้แสดงวิธีตั้งค่าข้อมูลจำนวนก้าว

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

บันทึกที่มีหน่วยวัด

Health Connect สามารถจัดเก็บค่าพร้อมกับหน่วยวัดเพื่อมอบความแม่นยำ ตัวอย่างหนึ่งคือประเภทข้อมูลโภชนาการซึ่งมีข้อมูลมากมายและครอบคลุม โดยมีฟิลด์สารอาหารเสริมให้เลือกหลากหลายตั้งแต่คาร์โบไฮเดรตทั้งหมดไปจนถึงวิตามิน จุดข้อมูลแต่ละจุดแสดงถึงสารอาหารที่อาจได้รับจากการรับประทานอาหารหรือรายการอาหาร

ในข้อมูลประเภทนี้ สารอาหารทั้งหมดจะแสดงในหน่วยมวล ส่วน energy จะแสดงในหน่วยพลังงาน

ตัวอย่างต่อไปนี้แสดงวิธีตั้งค่าข้อมูลโภชนาการสำหรับผู้ใช้ที่กินกล้วย

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(
        device = Device(type = Device.TYPE_PHONE)
    )
)

บันทึกที่มีข้อมูลซีรีส์

Health Connect สามารถจัดเก็บรายการข้อมูลอนุกรมได้ ตัวอย่างเช่น ประเภทข้อมูลอัตราการเต้นของหัวใจที่บันทึกชุดตัวอย่างการเต้นของหัวใจ ที่ตรวจพบระหว่างการอ่าน

ในประเภทข้อมูลนี้ พารามิเตอร์ samples จะแสดงด้วยรายการตัวอย่างอัตราการเต้นของหัวใจ แต่ละตัวอย่างจะมีค่า beatsPerMinute และค่า time

ตัวอย่างต่อไปนี้แสดงวิธีตั้งค่าข้อมูลชุดอัตราการเต้นของหัวใจ

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(
        device = Device(type = Device.TYPE_WATCH)
    ))

ขอสิทธิ์จากผู้ใช้

หลังจากสร้างอินสแตนซ์ไคลเอ็นต์แล้ว แอปของคุณต้องขอสิทธิ์จากผู้ใช้ ผู้ใช้ต้องได้รับอนุญาตให้ให้หรือปฏิเสธสิทธิ์ได้ทุกเมื่อ โดยให้สร้างชุดสิทธิ์สำหรับประเภทข้อมูลที่จำเป็น ตรวจสอบว่าได้ประกาศสิทธิ์ในชุดดังกล่าวใน Android manifest ก่อน

val permissions =
    setOf(
        HealthPermission.getReadPermission(HeartRateRecord::class),
        HealthPermission.getWritePermission(HeartRateRecord::class),
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::class)
    )
ใช้ getGrantedPermissions เพื่อดูว่าแอปของคุณได้รับสิทธิ์ที่จำเป็นแล้วหรือไม่ หากไม่มี ให้ใช้ createRequestPermissionResultContract เพื่อขอสิทธิ์เหล่านั้น ซึ่งจะแสดงหน้าจอขอสิทธิ์ของ 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.") }
    }
}
เนื่องจากผู้ใช้สามารถให้หรือเพิกถอนสิทธิ์ได้ทุกเมื่อ แอปของคุณจึงต้อง ตรวจสอบสิทธิ์ทุกครั้งก่อนที่จะใช้สิทธิ์ และจัดการสถานการณ์ที่ สิทธิ์หายไป

เขียนข้อมูล

เวิร์กโฟลว์ทั่วไปอย่างหนึ่งใน Health Connect คือการเขียนข้อมูล หากต้องการเพิ่มระเบียน ให้ใช้ insertRecords

ตัวอย่างต่อไปนี้แสดงวิธีเขียนข้อมูลเพื่อแทรกจำนวนก้าว

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

อัปเดตข้อมูล

หากต้องการเปลี่ยนระเบียนอย่างน้อย 1 รายการ โดยเฉพาะเมื่อต้องการซิงค์ที่เก็บข้อมูลของแอปกับข้อมูลจาก Health Connect คุณสามารถอัปเดตข้อมูลได้ การอัปเดตข้อมูลที่มีอยู่ทำได้ 2 วิธี โดยขึ้นอยู่กับตัวระบุที่ใช้ค้นหาระเบียน

ข้อมูลเมตา

คุณควรตรวจสอบMetadataคลาสก่อน เนื่องจากจำเป็นเมื่ออัปเดตข้อมูล ในการสร้างแต่ละ Record ใน Health Connect จะมีฟิลด์ metadata คุณสมบัติต่อไปนี้เกี่ยวข้องกับการซิงค์

พร็อพเพอร์ตี้ คำอธิบาย
id Record ทุกรายการใน Health Connect มีค่า id ที่ไม่ซ้ำกัน
Health Connect จะสร้างข้อมูลนี้โดยอัตโนมัติ เมื่อแทรกระเบียนใหม่
lastModifiedTime Recordยังติดตามเวลาที่มีการแก้ไขระเบียนครั้งล่าสุดด้วย
Health Connect จะป้อนข้อมูลนี้โดยอัตโนมัติ
clientRecordId Record แต่ละรายการจะมีรหัสที่ไม่ซ้ำกันซึ่งเชื่อมโยงอยู่ เพื่อใช้เป็นข้อมูลอ้างอิงในที่เก็บข้อมูลแอป
แอปของคุณระบุค่านี้
clientRecordVersion ในกรณีที่ระเบียนมี clientRecordId คุณสามารถใช้ clientRecordVersion เพื่ออนุญาตให้ข้อมูล ซิงค์กับเวอร์ชันในที่เก็บข้อมูลของแอป ได้
แอปของคุณระบุค่านี้

อัปเดตหลังจากอ่านตามช่วงเวลา

หากต้องการอัปเดตข้อมูล ให้เตรียมระเบียนที่จำเป็นก่อน ทำการเปลี่ยนแปลงระเบียนหากจำเป็น จากนั้นโทรหา updateRecords เพื่อทำการเปลี่ยนแปลง

ตัวอย่างต่อไปนี้แสดงวิธีอัปเดตข้อมูล ด้วยเหตุนี้ ระบบจึงปรับค่าออฟเซ็ตโซนของแต่ละระเบียน เป็น 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
    }
}

อัปเดต/แทรกผ่านรหัสระเบียนลูกค้า

หากคุณใช้ค่ารหัสระเบียนไคลเอ็นต์และค่าเวอร์ชันระเบียนไคลเอ็นต์ที่ไม่บังคับ เราขอแนะนำให้ใช้ insertRecords แทน updateRecords

insertRecords ฟังก์ชันมีความสามารถในการแทรก/อัปเดตข้อมูล หากมีข้อมูลใน Health Connect ตามชุดรหัสบันทึกของลูกค้าที่ระบุ ระบบจะเขียนทับข้อมูลดังกล่าว ไม่เช่นนั้น ระบบจะเขียนเป็นข้อมูลใหม่ สถานการณ์นี้มีประโยชน์เมื่อใดก็ตามที่คุณต้องการซิงค์ข้อมูลจาก ที่เก็บข้อมูลของแอปไปยัง Health Connect

ตัวอย่างต่อไปนี้แสดงวิธีดำเนินการ upsert ในข้อมูลที่ดึงมาจาก ที่เก็บข้อมูลของแอป

 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(
            clientRecordId = "Your client record ID",
            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
    }
}

หลังจากนั้น คุณจะเรียกใช้ฟังก์ชันเหล่านี้ในเทรดหลักได้

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

ตรวจสอบค่าในเวอร์ชันบันทึกของไคลเอ็นต์

หากกระบวนการแทรก/อัปเดตข้อมูลมี Client Record Version, Health Connect จะทำการตรวจสอบการเปรียบเทียบในclientRecordVersion ค่า หากเวอร์ชันจากข้อมูลที่แทรกสูงกว่า เวอร์ชันจากข้อมูลที่มีอยู่ ระบบจะแทรก/อัปเดตข้อมูล มิเช่นนั้น กระบวนการ จะละเว้นการเปลี่ยนแปลงและค่าจะยังคงเหมือนเดิม

หากต้องการรวมการกำหนดเวอร์ชันไว้ในข้อมูล คุณต้องระบุ Metadata.clientRecordVersion ที่มีค่า Long ตามตรรกะการกำหนดเวอร์ชัน

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(
        clientRecordId = "Your supplied record ID",
        clientRecordVersion = 0L, // Your supplied record version
        device = Device(type = Device.TYPE_WATCH)
    )
)

Upsert จะไม่เพิ่ม version โดยอัตโนมัติเมื่อมีการเปลี่ยนแปลง เพื่อป้องกันไม่ให้มีการเขียนทับข้อมูลโดยไม่คาดคิด ดังนั้นคุณจึงต้อง ระบุค่าที่สูงขึ้นด้วยตนเอง

คําแนะนําทั่วไป

แอปควรเขียนข้อมูลจากบุคคลที่หนึ่งที่รองรับทั้งหมด คุณอาจเลือกให้แอปเขียนข้อมูลที่ได้จากแหล่งที่มาของบุคคลที่สามก็ได้ อย่างไรก็ตาม หากแอปอ่านข้อมูลจาก Health Connect ข้อมูลดังกล่าวไม่ควรเขียนกลับลงใน Health Connect

เมื่อเขียนข้อมูลที่นำเข้าหรือได้มาจากแหล่งอื่น คุณ ต้องระบุแหล่งที่มาและข้อมูลเมตาของอุปกรณ์ต้นทางอย่างถูกต้อง โดยต้องระบุข้อมูลเมตาต่อไปนี้สำหรับแต่ละระเบียนที่เขียน

  • recordingMethod: สำหรับข้อมูลที่บันทึกโดยอัตโนมัติหรือด้วยตนเอง เรา คาดหวังว่าจะมีการอัปเดตวิธีการบันทึกให้สอดคล้องกับประเภทกิจกรรม ที่บันทึกไว้ ดังนี้
    • RECORDING_METHOD_AUTOMATICALLY_RECORDED: หากระบบบันทึกข้อมูลโดยอัตโนมัติ เช่น ฟิตเนสแบนด์ตรวจพบโดยอัตโนมัติว่าผู้ใช้ไปวิ่ง
    • RECORDING_METHOD_ACTIVELY_RECORDED: หากผู้ใช้เริ่มกิจกรรมใหม่ เช่น ปั่นจักรยานบนอุปกรณ์ที่สวมใส่ได้
    • RECORDING_METHOD_MANUAL_ENTRY: หากผู้ใช้ป้อนข้อมูลด้วยตนเอง
  • device.type: คุณต้องระบุประเภทอุปกรณ์จากประเภท Device ที่รองรับ
  • device.manufacturer: ผู้ผลิตอุปกรณ์ เช่น "Fitbit"
  • device.model: รุ่นของอุปกรณ์ เช่น "Charge 3"

การตั้งค่าข้อมูลเมตาอย่างถูกต้องเป็นสิ่งสำคัญอย่างยิ่งต่อความโปร่งใสของข้อมูลและช่วยให้ ผู้ใช้เข้าใจว่าข้อมูลสุขภาพของตนมาจากไหน ดูรายละเอียดทั้งหมดได้ที่ คู่มือข้อมูลเมตาของ Health Connect

หากมีการนำเข้าข้อมูลในแอปจากแอปอื่น แอปนั้นก็จะมีหน้าที่ เขียนข้อมูลของตัวเองลงใน Health Connect

นอกจากนี้ คุณควรใช้ตรรกะที่จัดการข้อยกเว้นในการเขียน เช่น ข้อมูลอยู่นอกขอบเขต หรือข้อผิดพลาดของระบบภายใน คุณสามารถใช้กลยุทธ์ Backoff และลองอีกครั้งกับกลไกการกำหนดเวลางานได้ หากการเขียนไปยัง Health Connect ไม่สำเร็จในท้ายที่สุด โปรดตรวจสอบว่าแอปสามารถข้ามจุดส่งออกนั้นได้ อย่าลืมบันทึกและรายงานข้อผิดพลาดเพื่อช่วยในการวินิจฉัย

เมื่อติดตามข้อมูล มีคำแนะนำ 2 ข้อที่คุณทำตามได้ ทั้งนี้ขึ้นอยู่กับวิธีที่แอปเขียนข้อมูล

การจัดการเขตเวลา

เมื่อเขียนบันทึกตามเวลา ให้หลีกเลี่ยงการตั้งค่าออฟเซ็ตเป็น zoneOffset.UTC โดยค่าเริ่มต้น เนื่องจากอาจทำให้การประทับเวลาไม่ถูกต้องเมื่อผู้ใช้อยู่ใน เขตเวลาอื่นๆ ให้คำนวณออฟเซ็ตตามตำแหน่งจริงของอุปกรณ์แทน คุณสามารถเรียกเขตเวลาของอุปกรณ์ได้โดยใช้ 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(),
    )
    sampleTime = sampleTime.plus(Duration.ofMinutes(minutesBetweenSamples))
}
healthConnectClient.insertRecords(
    stepsRecords
)

ดูรายละเอียดเพิ่มเติมได้ในเอกสารประกอบสำหรับ ZoneId

ความถี่และระดับรายละเอียดในการเขียน

เมื่อเขียนข้อมูลไปยัง Health Connect ให้ใช้ความละเอียดที่เหมาะสม การใช้ความละเอียดที่เหมาะสมจะช่วยลดภาระการจัดเก็บข้อมูล ในขณะที่ยังคงรักษาข้อมูลให้สอดคล้องและแม่นยำ ความละเอียดของข้อมูลครอบคลุม 2 สิ่งต่อไปนี้

  • ความถี่ในการเขียน: ความถี่ที่แอปพลิเคชันเขียนข้อมูลใหม่ลงใน Health Connect
    • เขียนข้อมูลบ่อยที่สุดเท่าที่จะทำได้เมื่อมีข้อมูลใหม่ พร้อมกับ คำนึงถึงประสิทธิภาพของอุปกรณ์
    • เพื่อไม่ให้ส่งผลเสียต่ออายุการใช้งานแบตเตอรี่และประสิทธิภาพด้านอื่นๆ ช่วงเวลาระหว่างการเขียนสูงสุดควรอยู่ที่ 15 นาที
  • ระดับความละเอียดของข้อมูลที่เขียน: ความถี่ในการสุ่มตัวอย่างข้อมูล
    • เช่น เขียนตัวอย่างอัตราการเต้นของหัวใจทุกๆ 5 วินาที
    • ข้อมูลแต่ละประเภทไม่จำเป็นต้องมีอัตราการสุ่มตัวอย่างเดียวกัน การอัปเดตข้อมูลจำนวนก้าวทุกวินาทีแทบจะไม่มีประโยชน์เลย เมื่อเทียบกับการอัปเดตที่ถี่น้อยกว่า เช่น ทุก 60 วินาที
    • อัตราการสุ่มตัวอย่างที่สูงขึ้นอาจช่วยให้ผู้ใช้เห็นข้อมูลสุขภาพและการออกกำลังกายของตนเองในรายละเอียดและแบบละเอียดมากขึ้น ความถี่ของอัตราการสุ่มตัวอย่างควรมีความสมดุลระหว่างรายละเอียดและประสิทธิภาพ

หลักเกณฑ์เพิ่มเติม

ทำตามหลักเกณฑ์ต่อไปนี้เมื่อเขียนข้อมูล

  • ในการซิงค์แต่ละครั้ง ให้เขียนเฉพาะข้อมูลใหม่และข้อมูลที่อัปเดตซึ่งมีการแก้ไขตั้งแต่ การซิงค์ครั้งล่าสุด
  • แบ่งคำขอเป็นกลุ่มๆ โดยมีระเบียนไม่เกิน 1,000 รายการต่อคำขอเขียน
  • จำกัดไม่ให้งานทำงานได้เฉพาะเมื่ออุปกรณ์ไม่ได้ใช้งานและแบตเตอรี่ไม่เหลือน้อย
  • สำหรับงานในเบื้องหลัง ให้ใช้ WorkManager เพื่อกำหนดเวลางานเป็นระยะ โดยมีระยะเวลาสูงสุด 15 นาที

โค้ดต่อไปนี้ใช้ WorkManager เพื่อกำหนดเวลาสำหรับงานในเบื้องหลังเป็นระยะ โดยมี ระยะเวลาสูงสุด 15 นาที และช่วงเวลาที่ยืดหยุ่น 5 นาที การกำหนดค่านี้ตั้งค่าโดยใช้คลาส PeriodicWorkRequest.Builder

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

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

การติดตามที่ใช้งานอยู่

ซึ่งรวมถึงแอปที่ทำการติดตามตามเหตุการณ์ เช่น การออกกำลังกายและการนอนหลับ หรือข้อมูลจากผู้ใช้ด้วยตนเอง เช่น โภชนาการ ระบบจะสร้างบันทึกเหล่านี้เมื่อแอป อยู่ในเบื้องหน้า หรือในกรณีที่เกิดขึ้นไม่บ่อยนักซึ่งมีการใช้งานแอป 2-3 ครั้งต่อวัน

ตรวจสอบว่าแอปไม่ได้เปิด Health Connect ไว้ตลอด ระยะเวลาของกิจกรรม

ต้องเขียนข้อมูลไปยัง Health Connect ด้วยวิธีใดวิธีหนึ่งต่อไปนี้

  • ซิงค์ข้อมูลกับ Health Connect หลังจากเหตุการณ์เสร็จสมบูรณ์แล้ว เช่น ซิงค์ข้อมูลเมื่อผู้ใช้สิ้นสุดเซสชันการออกกำลังกายที่ติดตาม
  • กำหนดเวลางานแบบครั้งเดียวโดยใช้ WorkManager เพื่อซิงค์ข้อมูลในภายหลัง

แนวทางปฏิบัติแนะนำสำหรับระดับความละเอียดและความถี่ในการเขียน

เมื่อเขียนข้อมูลไปยัง Health Connect ให้ใช้ความละเอียดที่เหมาะสม การใช้ความละเอียดที่เหมาะสมจะช่วยลดภาระการจัดเก็บข้อมูล ในขณะที่ยังคงรักษาข้อมูลให้สอดคล้องและแม่นยำ ความละเอียดของข้อมูลครอบคลุม 2 สิ่งต่อไปนี้

  1. ความถี่ในการเขียน: ความถี่ที่แอปพลิเคชันของคุณพุชข้อมูลใหม่ลงใน Health Connect เขียนข้อมูลบ่อยที่สุดเท่าที่จะเป็นไปได้เมื่อมีข้อมูลใหม่ พร้อมใช้งาน โดยคำนึงถึงประสิทธิภาพของอุปกรณ์ด้วย เพื่อไม่ให้ส่งผลเสียต่อ อายุการใช้งานแบตเตอรี่และด้านประสิทธิภาพอื่นๆ ช่วงเวลาสูงสุด ระหว่างการเขียนควรอยู่ที่ 15 นาที

  2. ระดับความละเอียดของข้อมูลที่เขียน: ความถี่ในการสุ่มตัวอย่างข้อมูลที่พุชเข้ามา เช่น เขียนตัวอย่างอัตราการเต้นของหัวใจทุกๆ 5 วินาที ข้อมูลบางประเภท ไม่จำเป็นต้องมีอัตราการสุ่มตัวอย่างเดียวกัน การอัปเดตข้อมูลจำนวนก้าวทุกวินาทีแทบไม่มีประโยชน์ เมื่อเทียบกับการอัปเดตที่ถี่น้อยกว่า เช่น ทุก 60 วินาที อย่างไรก็ตาม อัตราการสุ่มตัวอย่างที่สูงขึ้นอาจช่วยให้ผู้ใช้เห็นข้อมูลสุขภาพและการออกกำลังกายของตนเองได้ละเอียดและ เฉพาะเจาะจงมากขึ้น ความถี่ของอัตราการสุ่มตัวอย่าง ควรมีความสมดุลระหว่างรายละเอียดและประสิทธิภาพ

สร้างโครงสร้างระเบียนสำหรับข้อมูลซีรีส์

สำหรับประเภทข้อมูลที่ใช้ชุดตัวอย่าง เช่น HeartRateRecord คุณควรจัดโครงสร้างระเบียนให้ถูกต้อง คุณควรสร้างบันทึกขนาดเล็กหลายรายการแทนการสร้างบันทึกเดียวที่ยาวตลอดทั้งวันและมีการอัปเดตอยู่เสมอ โดยแต่ละบันทึกจะแสดงช่วงเวลาที่เฉพาะเจาะจง

เช่น สำหรับข้อมูลอัตราการเต้นของหัวใจ คุณควรสร้าง HeartRateRecord ใหม่ ทุกนาที แต่ละระเบียนจะมีเวลาเริ่มต้นและเวลาสิ้นสุดที่ครอบคลุมนาทีนั้นๆ และจะมีตัวอย่างอัตราการเต้นของหัวใจทั้งหมดที่บันทึกไว้ในนาทีนั้นๆ

ในระหว่างการซิงค์กับ Health Connect เป็นประจำ (เช่น ทุกๆ 15 นาที) แอปของคุณควรเขียนบันทึก 1 นาทีทั้งหมดที่สร้างขึ้นตั้งแต่การซิงค์ครั้งก่อน ซึ่งจะช่วยให้บันทึกมีขนาดที่จัดการได้และปรับปรุงประสิทธิภาพการค้นหาและการประมวลผลข้อมูล

ตัวอย่างต่อไปนี้แสดงวิธีสร้าง HeartRateRecord เป็นเวลา 1 นาที โดยมีตัวอย่างหลายรายการ

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(
        device = Device(type = Device.TYPE_WATCH)
    ))

เขียนข้อมูลที่ตรวจสอบตลอดทั้งวัน

สำหรับข้อมูลที่รวบรวมอย่างต่อเนื่อง เช่น จำนวนก้าว แอปพลิเคชันควร เขียนไปยัง Health Connect บ่อยที่สุดเท่าที่จะเป็นไปได้เมื่อมีข้อมูลใหม่ เพื่อไม่ให้ส่งผลเสียต่ออายุการใช้งานแบตเตอรี่และประสิทธิภาพด้านอื่นๆ ช่วงเวลาสูงสุดระหว่างการเขียนควรอยู่ที่ 15 นาที

ตารางที่ 1: คำแนะนำในการเขียนข้อมูล

ประเภทข้อมูล

หน่วย

คาดการณ์

ตัวอย่าง

ขั้นตอน

ขั้นตอน

ทุกๆ 1 นาที

23:14 - 23:15 - 5 ขั้นตอน

23:16 - 23:17 - 22 ขั้น

23:17 - 23:18 - 8 ขั้นตอน

StepsCadence

ก้าว/นาที

ทุกๆ 1 นาที

23:14 - 23:15 - 5 spm

23:16 - 23:17 - 22 spm

23:17 - 23:18 - 8 spm

การทำวีลแชร์พุช

พุช

ทุกๆ 1 นาที

23:14 - 23:15 - 5 ครั้ง

23:16 - 23:17 - 22 pushes

23:17 - 23:18 - 8 pushes

ActiveCaloriesBurned

แคลอรี่

ทุก 15 นาที

23:15 - 23:30 - 2 แคลอรี่

23:30 - 23:45 - 25 แคลอรี่

23:45 - 00:00 - 5 แคลอรี่

TotalCaloriesBurned

แคลอรี่

ทุก 15 นาที

23:15 - 23:30 - 16 แคลอรี่

23:30 - 23:45 - 16 แคลอรี่

23:45 - 00:00 - 16 แคลอรี่

ระยะทาง

กม./นาที

ทุกๆ 1 นาที

23:14-23:15 - 0.008 กม.

23:16 - 23:16 - 0.021 กม.

23:17 - 23:18 - 0.012 กม.

ElevationGained

ม.

ทุกๆ 1 นาที

20:36 - 20:37 - 3.048 ม.

20:39 - 20:40 - 3.048m

23:23 - 23:24 - 9.144m

จำนวนชั้นที่เดินขึ้น

ชั้น

ทุกๆ 1 นาที

23:14 - 23:15 - 5 ชั้น

23:16 - 23:16 - 22 ชั้น

23:17 - 23:18 - 8 ชั้น

HeartRate

bpm

4 ครั้งต่อนาที

06:11:15 น. - 55 bpm

06:11:30 น. - 56 bpm

06:11:45 น. - 56 bpm

06:12:00 น. - 55 bpm

HeartRateVariabilityRmssd

มิลลิวินาที

ทุกๆ 1 นาที

06:11 น. - 23 มิลลิวินาที

RespiratoryRate

ครั้ง/นาที

ทุกๆ 1 นาที

23:14 - 23:15 - หายใจ 60 ครั้ง/นาที

23:16 - 23:16 - 62 ครั้ง/นาที

23:17 - 23:18 - 64 ครั้ง/นาที

ความอิ่มตัวของออกซิเจน

%

ทุกๆ 1 ชั่วโมง

6:11 - 95.208%

ควรเขียนข้อมูลลงใน Health Connect เมื่อสิ้นสุดเซสชันการออกกำลังกายหรือการนอนหลับ สำหรับการติดตามที่ใช้งานอยู่ เช่น การออกกำลังกายและการนอนหลับ หรือข้อมูลจากผู้ใช้ด้วยตนเอง เช่น โภชนาการ ระบบจะสร้างระเบียนเหล่านี้เมื่อแอปอยู่ในเบื้องหน้า หรือในกรณีที่เกิดขึ้นไม่บ่อยนักซึ่งมีการใช้งาน 2-3 ครั้งต่อวัน

ตรวจสอบว่าแอปไม่ได้เรียกใช้ Health Connect ตลอดระยะเวลาของกิจกรรม

ต้องเขียนข้อมูลไปยัง Health Connect ด้วยวิธีใดวิธีหนึ่งต่อไปนี้

  • ซิงค์ข้อมูลกับ Health Connect หลังจากเหตุการณ์เสร็จสมบูรณ์แล้ว เช่น ซิงค์ข้อมูลเมื่อผู้ใช้สิ้นสุดเซสชันการออกกำลังกายที่ติดตาม
  • ตั้งเวลางานแบบครั้งเดียวโดยใช้ WorkManager เพื่อซิงค์ข้อมูลในภายหลัง

เซสชันการออกกำลังกายและการนอนหลับ

แอปพลิเคชันของคุณควรปฏิบัติตามคำแนะนำในคอลัมน์คาดการณ์ ในตารางที่ 2 เป็นอย่างน้อย และหากเป็นไปได้ ให้ปฏิบัติตามคำแนะนำในคอลัมน์ดีที่สุด

ตารางต่อไปนี้แสดงวิธีเขียนข้อมูลระหว่างการออกกำลังกาย

ตารางที่ 2: คำแนะนำในการเขียนข้อมูลระหว่างเซสชันการออกกำลังกาย

ประเภทข้อมูล

หน่วย

คาดการณ์

ขอแสดงความนับถือ

ตัวอย่าง

ขั้นตอน

ขั้นตอน

ทุกๆ 1 นาที

ทุกๆ 1 วินาที

23:14-23:15 - 5 ขั้นตอน

23:16 - 23:17 - 22 ขั้น

23:17 - 23:18 - 8 ขั้นตอน

StepsCadence

ก้าว/นาที

ทุกๆ 1 นาที

ทุกๆ 1 วินาที

23:14-23:15 - 35 spm

23:16 - 23:17 - 37 spm

23:17 - 23:18 - 40 spm

การทำวีลแชร์พุช

พุช

ทุกๆ 1 นาที

ทุกๆ 1 วินาที

23:14-23:15 - 5 ครั้ง

23:16 - 23:17 - 22 pushes

23:17 - 23:18 - 8 pushes

CyclingPedalingCadence

rpm

ทุกๆ 1 นาที

ทุกๆ 1 วินาที

23:14-23:15 - 65 รอบต่อนาที

23:16 - 23:17 - 70 รอบต่อนาที

23:17 - 23:18 - 68 รอบต่อนาที

กำลังไฟ

วัตต์

ทุกๆ 1 นาที

ทุกๆ 1 วินาที

23:14-23:15 - 250 วัตต์

23:16 - 23:17 - 255 วัตต์

23:17 - 23:18 - 245 วัตต์

ความเร็ว

กม./นาที

ทุกๆ 1 นาที

ทุกๆ 1 วินาที

23:14-23:15 - 0.3 กม./นาที

23:16 - 23:17 - 0.4 กม./นาที

23:17 - 23:18 -0.4 กม./นาที

ระยะทาง

กม./ม.

ทุกๆ 1 นาที

ทุกๆ 1 วินาที

23:14-23:15 - 0.008 กม.

23:16 - 23:16 - 0.021 กม.

23:17 - 23:18 - 0.012 กม.

ActiveCaloriesBurned

แคลอรี่

ทุกๆ 1 นาที

ทุกๆ 1 วินาที

23:14-23:15 - 20 แคลอรี่

23:16 - 23:17 - 20 แคลอรี่

23:17 - 23:18 - 25 แคลอรี่

TotalCaloriesBurned

แคลอรี่

ทุกๆ 1 นาที

ทุกๆ 1 วินาที

23:14-23:15 - 36 แคลอรี่

23:16 - 23:17 - 36 แคลอรี่

23:17 - 23:18 - 41 แคลอรี่

ElevationGained

ม.

ทุกๆ 1 นาที

ทุกๆ 1 วินาที

20:36 - 20:37 - 3.048 ม.

20:39 - 20:40 - 3.048m

23:23 - 23:24 - 9.144m

ExerciseRoutes

lat/lng/alt

ทุก 3-5 วินาที

ทุกๆ 1 วินาที

HeartRate

bpm

4 ครั้งต่อนาที

ทุกๆ 1 วินาที

23:14-23:15 - 150 bpm

ตารางที่ 3 แสดงวิธีเขียนข้อมูลในระหว่างหรือหลังเซสชันการนอนหลับ

ตารางที่ 3: คำแนะนำในการเขียนข้อมูลระหว่างหรือหลังเซสชันการนอนหลับ

ประเภทข้อมูล

หน่วย

ตัวอย่างที่คาดไว้

ตัวอย่าง

การแบ่งระยะการนอนหลับ

เก็บพักไว้

ระยะเวลาแบบละเอียดต่อระยะการนอนหลับ

23:46 - 23:50 - ตื่น

23:50 - 23:56 - หลับตื้น

23:56 - 00:16 - หลับลึก

อัตราการเต้นของหัวใจขณะพัก

bpm

ค่ารายวันเดียว (คาดว่าจะได้รับในตอนเช้า)

06:11 น. - 60 bpm

ความอิ่มตัวของออกซิเจน

%

ค่ารายวันเดียว (คาดว่าจะได้รับในตอนเช้า)

6:11 - 95.208%

การแข่งขันกีฬาหลายประเภท

แนวทางนี้ใช้ประเภทและโครงสร้างข้อมูลที่มีอยู่ และตรวจสอบความเข้ากันได้กับการติดตั้งใช้งาน Health Connect และเครื่องมืออ่านข้อมูลในปัจจุบัน ซึ่งเป็นแนวทางทั่วไปที่แพลตฟอร์มฟิตเนสใช้

นอกจากนี้ เซสชันแต่ละรายการ เช่น ว่ายน้ำ ปั่นจักรยาน และวิ่ง จะไม่ได้ลิงก์โดยตรงภายใน Health Connect และโปรแกรมอ่านข้อมูลต้องอนุมานความสัมพันธ์ระหว่างเซสชันเหล่านี้ตามความใกล้เคียงของเวลา ระบบจะไม่แสดงการเปลี่ยนผ่านระหว่างช่วงต่างๆ อย่างชัดเจน เช่น จากการว่ายน้ำไปปั่นจักรยาน

ตัวอย่างต่อไปนี้แสดงวิธีเขียนข้อมูลสำหรับการแข่งขันไตรกีฬา

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(
        device = Device(type = Device.TYPE_WATCH)
    ),
    startZoneOffset = null,
    endZoneOffset = null,
)

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

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

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

จัดการข้อยกเว้น

Health Connect จะส่งข้อยกเว้นมาตรฐานสำหรับการดำเนินการ CRUD เมื่อพบปัญหา แอปของคุณควรตรวจหาและจัดการข้อยกเว้นแต่ละรายการเหล่านี้ตาม ความเหมาะสม

แต่ละเมธอดใน HealthConnectClient แสดงข้อยกเว้นที่อาจเกิดขึ้น โดยทั่วไปแล้ว แอปควรจัดการข้อยกเว้นต่อไปนี้

ตารางที่ 1: ข้อยกเว้นของ Health Connect และแนวทางปฏิบัติแนะนำ
ข้อยกเว้น คำอธิบาย แนวทางปฏิบัติแนะนำ
IllegalStateException เกิดสถานการณ์ใดสถานการณ์หนึ่งต่อไปนี้

  • บริการ Health Connect ไม่พร้อมใช้งาน
  • คำขอไม่ใช่โครงสร้างที่ถูกต้อง เช่น คำขอรวมใน ที่เก็บข้อมูลเป็นระยะๆ ซึ่งใช้Instantออบเจ็กต์สำหรับtimeRangeFilter

จัดการปัญหาที่อาจเกิดขึ้นกับอินพุตก่อนที่จะส่งคำขอ คุณควรกำหนดค่าให้กับตัวแปรหรือใช้ตัวแปรเป็นพารามิเตอร์ภายในฟังก์ชันที่กำหนดเองแทนที่จะใช้ตัวแปรโดยตรงในคำขอ เพื่อให้คุณใช้กลยุทธ์การจัดการข้อผิดพลาดได้
IOException พบปัญหาในการอ่านและเขียนข้อมูลจาก ดิสก์ หากต้องการหลีกเลี่ยงปัญหานี้ โปรดดูคำแนะนำต่อไปนี้

  • สำรองข้อมูลจากผู้ใช้
  • สามารถจัดการปัญหาที่เกิดขึ้นระหว่างการดำเนินการเขียนแบบกลุ่มได้ เช่น ตรวจสอบว่ากระบวนการข้ามปัญหาและดำเนินการที่เหลือได้
  • ใช้กลยุทธ์การลองใหม่และการหยุดชั่วคราวเพื่อจัดการปัญหาคำขอ

RemoteException เกิดข้อผิดพลาดภายในหรือในการสื่อสารกับบริการพื้นฐานที่ SDK เชื่อมต่อ

เช่น แอปของคุณพยายามลบบันทึกที่มี uid ที่ระบุ อย่างไรก็ตาม ระบบจะส่งข้อยกเว้น หลังจากที่แอปพบเมื่อตรวจสอบในบริการพื้นฐานว่า ไม่มีบันทึกดังกล่าว
หากต้องการหลีกเลี่ยงปัญหานี้ โปรดดูคำแนะนำต่อไปนี้

  • ซิงค์ที่เก็บข้อมูลของแอปกับ Health Connect เป็นประจำ
  • ใช้กลยุทธ์การลองใหม่และการหยุดชั่วคราวเพื่อจัดการปัญหาคำขอ

SecurityException มีปัญหาเกิดขึ้นเมื่อคำขอต้องใช้สิทธิ์ที่ไม่ได้ให้ หากต้องการหลีกเลี่ยงปัญหานี้ โปรดตรวจสอบว่าคุณได้ ประกาศการใช้ประเภทข้อมูล Health Connect สำหรับแอปที่เผยแพร่แล้ว นอกจากนี้ คุณต้องประกาศสิทธิ์ของ Health Connect ในไฟล์ Manifest และในกิจกรรมของคุณ