คู่มือนี้ใช้ได้กับ Health Connect เวอร์ชัน 1.1.0-alpha12 ขึ้นไป
แอปส่วนใหญ่ที่ผสานรวมกับ Health Connect มีที่เก็บข้อมูลของตนเองซึ่งทำหน้าที่เป็นแหล่งข้อมูลที่เชื่อถือได้ Health Connect มีวิธีต่างๆ ที่จะช่วยให้แอปของคุณซิงค์อยู่เสมอ
กระบวนการซิงค์อาจเกี่ยวข้องกับการดำเนินการบางอย่างหรือทั้งหมดต่อไปนี้ ทั้งนี้ขึ้นอยู่กับสถาปัตยกรรมของแอป
- ป้อนข้อมูลใหม่หรือข้อมูลที่อัปเดตจาก Datastore ของแอปไปยัง Health Connect
- ดึงการเปลี่ยนแปลงข้อมูลจาก Health Connect ไปยัง Datastore ของแอป
- ลบข้อมูลออกจาก Health Connect เมื่อมีการลบข้อมูลในที่เก็บข้อมูลของแอป
ในแต่ละกรณี โปรดตรวจสอบว่ากระบวนการซิงค์ทำให้ทั้ง Health Connect และพื้นที่เก็บข้อมูลของแอปสอดคล้องกัน
ป้อนข้อมูลไปยัง Health Connect
ส่วนแรกของกระบวนการซิงค์คือการป้อนข้อมูลจากที่เก็บข้อมูลของแอปไปยังที่เก็บข้อมูลของ Health Connect
เตรียมข้อมูลของคุณ
โดยปกติแล้ว ระเบียนใน Datastore ของแอปจะมีรายละเอียดต่อไปนี้
- คีย์ที่ไม่ซ้ำกัน เช่น
UUID - เวอร์ชันหรือการประทับเวลา
เมื่อซิงค์ข้อมูลกับ Health Connect ให้ระบุและป้อนเฉพาะข้อมูลที่มีการแทรก อัปเดต หรือลบตั้งแต่การซิงค์ครั้งล่าสุด
เขียนข้อมูลลงใน Health Connect
หากต้องการป้อนข้อมูลลงใน Health Connect ให้ทำตามขั้นตอนต่อไปนี้
- รับรายการข้อมูลใหม่ ข้อมูลที่อัปเดต หรือข้อมูลที่ลบออกจาก Datastore ของแอป
- สำหรับแต่ละรายการ ให้สร้างออบเจ็กต์
Recordที่เหมาะกับประเภทข้อมูลนั้น เช่น สร้างออบเจ็กต์WeightRecordสำหรับข้อมูลที่เกี่ยวข้องกับน้ำหนัก ระบุออบเจ็กต์
Metadataด้วยRecordแต่ละรายการ ซึ่งรวมถึงclientRecordIdซึ่งเป็นรหัสจากที่เก็บข้อมูลของแอปที่คุณใช้เพื่อระบุระเบียนที่ไม่ซ้ำกันได้ คุณสามารถใช้คีย์ที่ไม่ซ้ำกันที่มีอยู่เพื่อดำเนินการนี้ได้ หากข้อมูลของคุณมีการกำหนดเวอร์ชัน ให้ระบุclientRecordVersionที่สอดคล้องกับการกำหนดเวอร์ชันที่ใช้ในข้อมูลด้วย หากไม่มีเวอร์ชัน คุณสามารถใช้ค่าLongของการประทับเวลาปัจจุบันเป็นทางเลือกได้val recordVersion = 0L // Specify as needed // The clientRecordId is an ID that you choose for your record. This // is often the same ID you use in your app's datastore. val clientRecordId = "<your-record-id>" val record = WeightRecord( metadata = Metadata.activelyRecorded( clientRecordId = clientRecordId, clientRecordVersion = recordVersion, device = Device(type = Device.TYPE_SCALE) ), weight = Mass.kilograms(62.0), time = Instant.now(), zoneOffset = ZoneOffset.UTC, ) healthConnectClient.insertRecords(listOf(record))
อัปเดตหรือแทรกข้อมูลลงใน Health Connect โดยใช้
insertRecordsการอัปเดตข้อมูลหมายความว่าข้อมูลที่มีอยู่ใน Health Connect จะถูกเขียนทับตราบใดที่ค่าclientRecordIdยังคงอยู่ในที่เก็บข้อมูลของ Health Connect และค่าclientRecordVersionสูงกว่าค่าที่มีอยู่ ไม่เช่นนั้น ระบบจะเขียนข้อมูลที่อัปเดตและแทรกเป็นข้อมูลใหม่healthConnectClient.insertRecords(arrayListOf(record))
หากต้องการดูข้อควรพิจารณาในทางปฏิบัติสำหรับการป้อนข้อมูล โปรดดูแนวทางปฏิบัติแนะนำสำหรับการเขียนข้อมูล
จัดเก็บรหัส Health Connect
หากแอปของคุณอ่านข้อมูลจาก Health Connect ด้วย ให้จัดเก็บ id ของ Health Connect สำหรับบันทึกหลังจากที่อัปเดตหรือแทรกข้อมูลแล้ว คุณต้องใช้ id นี้เพื่อประมวลผลการลบเมื่อดึงการเปลี่ยนแปลงข้อมูลจาก Health Connect
ฟังก์ชัน insertRecords จะแสดงผล InsertRecordsResponse ที่มีรายการค่า id
ใช้การตอบกลับเพื่อรับรหัสระเบียนและจัดเก็บไว้
val response = healthConnectClient.insertRecords(listOf(record)) for (recordId in response.recordIdsList) { // Store recordId to your app's datastore }
ดึงข้อมูลจาก Health Connect
ส่วนที่ 2 ของกระบวนการซิงค์คือการดึงข้อมูลการเปลี่ยนแปลงจาก Health Connect ไปยัง Datastore ของแอป การเปลี่ยนแปลงข้อมูลอาจรวมถึงการอัปเดตและการลบ
รับโทเค็นการเปลี่ยนแปลง
หากต้องการดูรายการการเปลี่ยนแปลงที่จะดึงมาจาก Health Connect แอปของคุณจะต้องติดตามโทเค็น Changes คุณสามารถใช้โทเค็นเหล่านี้เมื่อส่งคำขอ Changes เพื่อแสดงทั้งรายการการเปลี่ยนแปลงข้อมูลและโทเค็น Changes ใหม่ที่จะใช้ในครั้งถัดไป
หากต้องการรับโทเค็น Changes ให้เรียกใช้ getChangesToken และระบุประเภทข้อมูลที่จำเป็น
val changesToken = healthConnectClient.getChangesToken( ChangesTokenRequest(recordTypes = setOf(WeightRecord::class)) )
ตรวจสอบการเปลี่ยนแปลงข้อมูล
เมื่อได้รับโทเค็น Changes แล้ว ให้ใช้โทเค็นดังกล่าวเพื่อรับ Changes ทั้งหมด เราขอแนะนำให้สร้างลูปเพื่อดูการเปลี่ยนแปลงทั้งหมดที่ตรวจสอบว่ามีการเปลี่ยนแปลงข้อมูลหรือไม่ ขั้นตอนมีดังนี้
- เรียกใช้
getChangesโดยใช้โทเค็นเพื่อรับรายการการเปลี่ยนแปลง - ตรวจสอบการเปลี่ยนแปลงแต่ละรายการว่าประเภทการเปลี่ยนแปลงเป็น
UpsertionChangeหรือDeletionChangeและดำเนินการที่จำเป็น- สำหรับ
UpsertionChangeให้ใช้เฉพาะการเปลี่ยนแปลงที่ไม่ได้มาจากแอปการโทรเพื่อให้แน่ใจว่าคุณไม่ได้นำเข้าข้อมูลซ้ำ
- สำหรับ
- กำหนดโทเค็น Changes ถัดไปเป็นโทเค็นใหม่
- ทำขั้นตอนที่ 1-3 ซ้ำจนกว่าจะไม่มีการเปลี่ยนแปลงเหลืออยู่
- จัดเก็บโทเค็นถัดไปและสำรองไว้สำหรับการนำเข้าในอนาคต
suspend fun processChanges(context: Context, token: String): String { var nextChangesToken = token do { val response = healthConnectClient.getChanges(nextChangesToken) response.changes.forEach { change -> when (change) { is UpsertionChange -> if (change.record.metadata.dataOrigin.packageName != context.packageName) { processUpsertionChange(change) } is DeletionChange -> processDeletionChange(change) } } nextChangesToken = response.nextChangesToken } while (response.hasMore) // Return and store the changes token for use next time. return nextChangesToken }
หากต้องการดูข้อควรพิจารณาในทางปฏิบัติสำหรับการดึงข้อมูล โปรดดูแนวทางปฏิบัติแนะนำสำหรับการซิงค์ข้อมูล
ประมวลผลการเปลี่ยนแปลงข้อมูล
แสดงการเปลี่ยนแปลงใน Datastore ของแอป สำหรับ UpsertionChange ให้ใช้ id และ lastModifiedTime จาก metadata เพื่ออัปเดตหรือแทรกระเบียน
สำหรับ DeletionChange ให้ใช้ id ที่ระบุไว้เพื่อลบระเบียน
ซึ่งกำหนดให้คุณต้องจัดเก็บระเบียน id ตามที่ระบุไว้ในจัดเก็บรหัส Health Connect
ลบข้อมูลออกจาก Health Connect
เมื่อผู้ใช้ลบข้อมูลของตนเองออกจากแอปของคุณ โปรดตรวจสอบว่าข้อมูลดังกล่าวถูกนำออกจาก Health Connect ด้วย ใช้ deleteRecords เพื่อดำเนินการนี้ ซึ่งจะใช้ประเภทระเบียนและรายการค่า id และ clientRecordId ซึ่งช่วยให้จัดกลุ่มข้อมูลหลายรายการเพื่อลบได้อย่างสะดวก นอกจากนี้ยังมี deleteRecords ทางเลือกที่ใช้ timeRangeFilter ด้วย
การซิงค์ที่มีเวลาในการตอบสนองต่ำจากอุปกรณ์ที่สวมใส่ได้
หากต้องการซิงค์ข้อมูลจากอุปกรณ์ออกกำลังกายที่สวมใส่ได้ไปยัง Health Connect โดยมีเวลาในการตอบสนองต่ำ ให้ใช้ CompanionDeviceService วิธีนี้ใช้ได้กับอุปกรณ์ที่รองรับการแจ้งเตือนหรือการระบุ BLE GATT และกำหนดเป้าหมายเป็น Android 8.0 (ระดับ API 26) ขึ้นไป CompanionDeviceService ช่วยให้แอปของคุณรับข้อมูลจากอุปกรณ์ที่สวมใส่ได้และเขียนลงใน Health Connect แม้ว่าแอปจะไม่ได้ทำงานอยู่ก็ตาม ดูรายละเอียดเพิ่มเติมเกี่ยวกับแนวทางปฏิบัติแนะนำสำหรับ BLE ได้ที่ภาพรวมของบลูทูธพลังงานต่ำ
เชื่อมโยงอุปกรณ์
ก่อนอื่น แอปของคุณต้องแนะนำผู้ใช้ตลอดกระบวนการแบบครั้งเดียวเพื่อเชื่อมโยงอุปกรณ์ที่สวมใส่ได้กับแอปโดยใช้ CompanionDeviceManager ซึ่งจะให้สิทธิ์ที่จำเป็นแก่แอปในการโต้ตอบกับอุปกรณ์ ดูข้อมูลเพิ่มเติมได้ที่การจับคู่อุปกรณ์ที่ใช้ร่วมกัน
ประกาศบริการในไฟล์ Manifest
ถัดไป ให้ประกาศ CompanionDeviceService ในไฟล์ Manifest ของแอป เพิ่มโค้ดต่อไปนี้ใน AndroidManifest.xml
<manifest ...>
<application ...>
<service
android:name=".MyWearableService"
android:exported="true"
android:permission="android.permission.BIND_COMPANION_DEVICE_SERVICE">
<intent-filter>
<action android:name="android.companion.CompanionDeviceService" />
</intent-filter>
</service>
</application>
</manifest>
สร้าง CompanionDeviceService
สุดท้าย ให้สร้างคลาสที่ขยาย CompanionDeviceService บริการนี้จะจัดการการเชื่อมต่อกับอุปกรณ์ที่สวมใส่ได้และรับข้อมูลผ่าน Callback ของ BLE GATT เมื่อได้รับข้อมูลใหม่ ระบบจะเขียนข้อมูลลงใน Health Connect ทันที
private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) private var healthConnectClient: HealthConnectClient? = null private var bluetoothGatt: BluetoothGatt? = null override fun onDeviceAppeared(address: String) { super.onDeviceAppeared(address) healthConnectClient = HealthConnectClient.getOrCreate(this) serviceScope.launch { val granted = healthConnectClient?.permissionController?.getGrantedPermissions() // 1. Check permissions ONCE when the device connects if (granted?.contains(HealthPermission.getWritePermission(HeartRateRecord::class)) ?: false) { // This is where you'd actually start the Bluetooth connection // bluetoothGatt = gattCallback.connect(...) } // 2. Do your initial database read readExerciseSessionAndRoute() } } private val gattCallback = object : BluetoothGattCallback() { override fun onCharacteristicChanged( gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray ) { super.onCharacteristicChanged(gatt, characteristic, value) // 3. ONLY process the incoming data here val rawData = value serviceScope.launch { // parseWearableData(rawData) // insertExerciseRoute() or writeToHealthConnect() } } }
แนวทางปฏิบัติแนะนำสำหรับการซิงค์ข้อมูล
ปัจจัยต่อไปนี้ส่งผลต่อกระบวนการซิงค์
การหมดอายุของโทเค็น
เนื่องจากโทเค็น Changes ที่ไม่ได้ใช้จะหมดอายุภายใน 30 วัน คุณจึงต้องใช้กลยุทธ์การซิงค์ที่หลีกเลี่ยงการสูญเสียข้อมูลในกรณีดังกล่าว กลยุทธ์ของคุณอาจรวมถึงแนวทางต่อไปนี้
- ค้นหา Datastore ของแอปเพื่อหารายการที่ใช้ล่าสุดซึ่งมี
idจาก Health Connect ด้วย - ขอระเบียนจาก Health Connect ที่ขึ้นต้นด้วยการประทับเวลาที่เฉพาะเจาะจง แล้วแทรกหรืออัปเดตระเบียนเหล่านั้นในที่เก็บข้อมูลของแอป
- ขอโทเค็นการเปลี่ยนแปลงเพื่อสำรองไว้ใช้ในครั้งถัดไปที่จำเป็น
กลยุทธ์การจัดการการเปลี่ยนแปลงที่แนะนำ
ในกรณีที่แอปของคุณได้รับโทเค็น Changes ที่ไม่ถูกต้องหรือหมดอายุ เราขอแนะนำกลยุทธ์การจัดการต่อไปนี้ โดยขึ้นอยู่กับการใช้งานในตรรกะของคุณ
- อ่านและกรองข้อมูลที่ซ้ำกันทั้งหมด กลยุทธ์นี้เป็นกลยุทธ์ที่เหมาะสมที่สุด
- จัดเก็บการประทับเวลาของครั้งล่าสุดที่อ่านข้อมูลจาก Health Connect
- เมื่อโทเค็นหมดอายุ ให้อ่านข้อมูลทั้งหมดอีกครั้งจากการประทับเวลาล่าสุดหรือในช่วง 30 วันที่ผ่านมา จากนั้นกรองข้อมูลที่ซ้ำกันออกจากข้อมูลที่อ่านก่อนหน้านี้โดยใช้ตัวระบุ
- เราขอแนะนำให้ติดตั้งใช้งานรหัสไคลเอ็นต์เนื่องจากจำเป็นสำหรับการอัปเดตข้อมูล
- อ่านเฉพาะข้อมูลตั้งแต่การประทับเวลาที่อ่านครั้งล่าสุด ซึ่งส่งผลให้ข้อมูลบางอย่างคลาดเคลื่อนในช่วงเวลาที่โทเค็นการเปลี่ยนแปลงหมดอายุ แต่ระยะเวลาจะสั้นลง โดยอาจใช้เวลา 2-3 ชั่วโมงถึง 2-3 วัน
- จัดเก็บการประทับเวลาของครั้งล่าสุดที่อ่านข้อมูลจาก Health Connect
- เมื่อโทเค็นหมดอายุ ให้อ่านข้อมูลทั้งหมดนับตั้งแต่การประทับเวลานี้เป็นต้นไป
- ลบแล้วอ่านข้อมูลในช่วง 30 วันที่ผ่านมา ซึ่งสอดคล้องกับสิ่งที่เกิดขึ้นในการผสานรวมครั้งแรกมากกว่า
- ลบข้อมูลทั้งหมดที่แอปอ่านจาก Health Connect ในช่วง 30 วันที่ผ่านมา
- เมื่อลบแล้ว ให้อ่านข้อมูลทั้งหมดนี้อีกครั้ง
- อ่านข้อมูลในช่วง 30 วันที่ผ่านมาโดยไม่กรองข้อมูลที่ซ้ำกันออก กลยุทธ์นี้เป็นกลยุทธ์ที่เหมาะสมน้อยที่สุด และส่งผลให้มีการแสดงข้อมูลที่ซ้ำกันต่อผู้ใช้
- ลบข้อมูลทั้งหมดที่แอปอ่านจาก Health Connect ในช่วง 30 วันที่ผ่านมา
- อนุญาตให้มีรายการซ้ำกัน
โทเค็นการเปลี่ยนแปลงประเภทข้อมูล
หากแอปใช้ข้อมูลมากกว่า 1 ประเภทแยกกัน ให้ใช้โทเค็นการเปลี่ยนแปลงแยกกันสำหรับข้อมูลแต่ละประเภท ใช้รายการประเภทข้อมูลหลายรายการกับ Changes Sync API เฉพาะในกรณีที่มีการใช้ประเภทข้อมูลเหล่านี้ร่วมกันหรือไม่มีการใช้เลย
การอ่านเบื้องหน้า
แอปจะอ่านข้อมูลจาก Health Connect ได้ขณะที่ทำงานอยู่เบื้องหน้าเท่านั้น เมื่อซิงค์ข้อมูลจาก Health Connect การเข้าถึง Health Connect อาจถูกขัดจังหวะได้ทุกเมื่อ ตัวอย่างเช่น แอปของคุณต้องจัดการกับการหยุดชะงักระหว่างการซิงค์เมื่ออ่านข้อมูลจำนวนมากจาก Health Connect และดำเนินการต่อในครั้งถัดไปที่เปิดแอป
การอ่านในเบื้องหลัง
คุณสามารถขอให้แอปพลิเคชันทำงานในเบื้องหลังและอ่านข้อมูลจาก Health Connect ได้ หากคุณขอสิทธิ์ Background Read ผู้ใช้จะให้สิทธิ์แอปของคุณในการอ่านข้อมูลในเบื้องหลังได้
นำเข้าช่วงเวลา
เนื่องจากแอปของคุณไม่สามารถรับการแจ้งเตือนเกี่ยวกับข้อมูลใหม่ได้ ให้ตรวจสอบข้อมูลใหม่ที่ 2 จุดต่อไปนี้
- ทุกครั้งที่แอปเริ่มทำงานในเบื้องหน้า ในกรณีนี้ ให้ใช้เหตุการณ์ในวงจร
- เป็นระยะๆ ขณะที่แอปยังคงทำงานอยู่เบื้องหน้า แจ้งเตือนผู้ใช้เมื่อมีข้อมูลใหม่ เพื่อให้ผู้ใช้อัปเดตหน้าจอเพื่อแสดงการเปลี่ยนแปลง