เขียนข้อมูล

คู่มือนี้ใช้ได้กับ 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)
    ))

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

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

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 รายการ โดยเฉพาะเมื่อคุณต้องการซิงค์ Datastore ของแอปกับข้อมูลจาก 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
    }
}

Upsert ผ่านรหัสระเบียนลูกค้า

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

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

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

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

การอัปเดตจะไม่เพิ่ม 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

นอกจากนี้ คุณควรใช้ตรรกะที่จัดการข้อยกเว้นการเขียน เช่น ข้อมูลอยู่นอกขอบเขต หรือข้อผิดพลาดของระบบภายใน คุณสามารถใช้กลยุทธ์ Backoff และลองใหม่ในกลไกการกำหนดเวลางานได้ หากเขียนลงใน 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 รายการต่อคำขอเขียน 1 รายการ
  • จำกัดให้งานทำงานเฉพาะเมื่ออุปกรณ์ไม่มีการใช้งานและแบตเตอรี่ไม่เหลือน้อย
  • สำหรับงานที่ทำงานอยู่เบื้องหลัง ให้ใช้ 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 ครั้งใน 1 วัน

ตรวจสอบว่าแอปของคุณไม่ได้ทำให้ Health Connect ทำงานตลอดระยะเวลาของเหตุการณ์

การเขียนข้อมูลลงใน Health Connect ต้องทำด้วยวิธีใดวิธีหนึ่งใน 2 วิธีต่อไปนี้

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

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

20:39 - 20:40 - 3.048 ม.

23:23 - 23:24 - 9.144 ม.

FloorsClimbed

ชั้น

ทุกๆ 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 นาที

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

RespiratoryRate

ครั้ง/นาที

ทุกๆ 1 นาที

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

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

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

OxygenSaturation

%

ทุกๆ 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 pushes

23:16 - 23:17 - วิดพื้น 22 ครั้ง

23:17 - 23:18 - 8 ครั้ง

CyclingPedalingCadence

rpm

ทุกๆ 1 นาที

ทุก 1 วินาที

23:14-23:15 - 65 rpm

23:16 - 23:17 - 70 rpm

23:17 - 23:18 - 68 rpm

กำลังไฟ

วัตต์

ทุกๆ 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.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 - หลับลึก

RestingHeartRate

bpm

ค่ารายวันเดียว (คาดว่าจะได้รับเป็นสิ่งแรกในตอนเช้า)

06:11 น. - 60 bpm

OxygenSaturation

%

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

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 พบปัญหาเมื่ออ่านและเขียนข้อมูลจากดิสก์ วิธีหลีกเลี่ยงปัญหานี้มีดังนี้

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

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

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

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

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