เขียนข้อมูล

คู่มือนี้ใช้ได้กับ 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.autoRecorded(
        device = Device(type = Device.TYPE_WATCH)
    )
)
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.activelyRecorded(
        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.activelyRecorded(
        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.autoRecorded(
        device = Device(type = Device.TYPE_WATCH)
    )
)
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 แต่ละรายการจะมีรหัสที่ไม่ซ้ำกันซึ่งเชื่อมโยงอยู่ เพื่อใช้เป็นข้อมูลอ้างอิงใน Datastore ของแอป
แอปของคุณระบุค่านี้
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.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
    }
}

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

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

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

หากกระบวนการแทรก/อัปเดตข้อมูลมีเวอร์ชันบันทึกของไคลเอ็นต์ 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.activelyRecorded(
        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"
  • device.udi: (ไม่บังคับ) ส่วนตัวระบุอุปกรณ์ (DI) ของตัวระบุอุปกรณ์ที่ไม่ซ้ำกัน (UDI) ของอุปกรณ์ทางการแพทย์ ดูรายละเอียดเกี่ยวกับสิทธิ์ที่จำเป็นและหลักเกณฑ์ด้านความเป็นส่วนตัวได้ในคู่มือข้อมูลเมตา

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

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

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

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

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

เมื่อเขียนบันทึกตามเวลา ให้หลีกเลี่ยงการตั้งค่าออฟเซ็ตเป็น 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.activelyRecorded(device = Device(type = Device.TYPE_WATCH)),
    )
    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 ด้วยวิธีใดวิธีหนึ่งใน 2 วิธีต่อไปนี้

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

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

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

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

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

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

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

เช่น สำหรับข้อมูลอัตราการเต้นของหัวใจ คุณควรสร้าง 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.activelyRecorded(
        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 รายการ

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.048m

20:39 - 20:40 - 3.048 ม.

23:23 - 23:24 - 9.144 ม.

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

ชั้น

ทุกๆ 1 นาที

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

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

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

HeartRate

bpm

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

06:11:15 น. - 55 bpm

6: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 ด้วยวิธีใดวิธีหนึ่งใน 2 วิธีต่อไปนี้

  • ซิงค์ข้อมูลกับ 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 รายการ

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.048m

20:39 - 20:40 - 3.048 ม.

23:23 - 23:24 - 9.144 ม.

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.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))

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

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

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

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

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

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

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

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

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

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

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