คู่มือนี้ใช้ได้กับ Health Connect เวอร์ชัน 1.1.0-alpha12
แอปส่วนใหญ่ที่ผสานรวมกับ Health Connect จะมีที่เก็บข้อมูลของตัวเองซึ่ง ทำหน้าที่เป็นแหล่งข้อมูลที่เชื่อถือได้ Health Connect มีวิธีช่วยให้แอป ซิงค์กันอยู่เสมอ
กระบวนการซิงค์อาจเกี่ยวข้องกับการดำเนินการต่อไปนี้บางส่วนหรือทั้งหมด ทั้งนี้ขึ้นอยู่กับสถาปัตยกรรมของแอป
- ป้อนข้อมูลใหม่หรือข้อมูลที่อัปเดตจากที่เก็บข้อมูลของแอปไปยัง Health Connect
- ดึงการเปลี่ยนแปลงข้อมูลจาก Health Connect ไปยังที่เก็บข้อมูลของแอป
- ลบข้อมูลออกจาก Health Connect เมื่อมีการลบข้อมูลในที่เก็บข้อมูลของแอป
ในแต่ละกรณี ให้ตรวจสอบว่ากระบวนการซิงค์ทำให้ Health Connect และที่เก็บข้อมูลของแอปสอดคล้องกัน
ป้อนข้อมูลไปยัง Health Connect
ส่วนแรกของกระบวนการซิงค์คือการป้อนข้อมูลจากที่เก็บข้อมูลของแอป ไปยังที่เก็บข้อมูลของ Health Connect
เตรียมข้อมูล
โดยปกติแล้ว บันทึกใน Datastore ของแอปจะมีรายละเอียดต่อไปนี้
- คีย์ที่ไม่ซ้ำกัน เช่น
UUID - เวอร์ชันหรือการประทับเวลา
เมื่อซิงค์ข้อมูลกับ Health Connect ให้ระบุและป้อนเฉพาะข้อมูลที่ แทรก อัปเดต หรือลบตั้งแต่การซิงค์ครั้งล่าสุด
เขียนข้อมูลไปยัง Health Connect
หากต้องการป้อนข้อมูลลงใน Health Connect ให้ทำตามขั้นตอนต่อไปนี้
- รับรายการข้อมูลใหม่ อัปเดต หรือลบจาก Datastore ของแอป
- สำหรับแต่ละรายการ ให้สร้างออบเจ็กต์
Recordที่เหมาะกับประเภทข้อมูลนั้น เช่น สร้างWeightRecordออบเจ็กต์สำหรับข้อมูลที่เกี่ยวข้องกับน้ำหนัก ระบุออบเจ็กต์
Metadataด้วยRecordแต่ละรายการ ซึ่งรวมถึงclientRecordIdซึ่งเป็นรหัสจาก Datastore ของแอปที่คุณใช้ เพื่อระบุระเบียนที่ไม่ซ้ำกันได้ คุณใช้คีย์ที่ไม่ซ้ำกันที่มีอยู่สำหรับ การดำเนินการนี้ได้ หากข้อมูลของคุณมีการควบคุมเวอร์ชัน ให้ระบุ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))Upsert ข้อมูลไปยัง 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(arrayListOf(record))
for (recordId in response.recordIdsList) {
// Store recordId to your app's datastore
}
ดึงข้อมูลจาก Health Connect
ส่วนที่ 2 ของกระบวนการซิงค์คือการดึงข้อมูลการเปลี่ยนแปลงจาก Health Connect ไปยังที่เก็บข้อมูลของแอป การเปลี่ยนแปลงข้อมูลอาจรวมถึงการอัปเดตและการลบ
รับโทเค็นการเปลี่ยนแปลง
หากต้องการดูรายการการเปลี่ยนแปลงที่จะดึงจาก Health Connect แอปของคุณต้องติดตามโทเค็นการเปลี่ยนแปลง คุณสามารถใช้โทเค็นเหล่านี้เมื่อขอการเปลี่ยนแปลงเพื่อรับทั้งรายการการเปลี่ยนแปลงข้อมูลและโทเค็นการเปลี่ยนแปลงใหม่ที่จะใช้ในครั้งถัดไป
หากต้องการรับโทเค็นการเปลี่ยนแปลง ให้เรียกใช้ getChangesToken และ
ระบุประเภทข้อมูลที่จำเป็น
val changesToken = healthConnectClient.getChangesToken(
ChangesTokenRequest(recordTypes = setOf(WeightRecord::class))
)
ตรวจสอบการเปลี่ยนแปลงข้อมูล
ตอนนี้คุณได้รับโทเค็นการเปลี่ยนแปลงแล้ว ให้ใช้โทเค็นดังกล่าวเพื่อรับการเปลี่ยนแปลงทั้งหมด เราขอแนะนำให้สร้างลูปเพื่อดูการเปลี่ยนแปลงทั้งหมด โดยจะตรวจสอบ ว่ามีการเปลี่ยนแปลงข้อมูลที่พร้อมใช้งานหรือไม่ ขั้นตอนมีดังนี้
- เรียกใช้
getChangesโดยใช้โทเค็นเพื่อรับรายการการเปลี่ยนแปลง - ตรวจสอบการเปลี่ยนแปลงแต่ละรายการว่าเป็นการเปลี่ยนแปลงประเภท
UpsertionChangeหรือDeletionChangeแล้ว ดำเนินการที่จำเป็น- สำหรับ
UpsertionChangeให้ใช้เฉพาะการเปลี่ยนแปลงที่ไม่ได้มาจากแอปโทรเพื่อไม่ให้นำเข้าข้อมูลซ้ำ
- สำหรับ
- กำหนดโทเค็น Changes ถัดไปเป็นโทเค็นใหม่
- ทำขั้นตอนที่ 1-3 ซ้ำจนกว่าจะไม่มีการเปลี่ยนแปลงเหลืออยู่
- จัดเก็บโทเค็นถัดไปและสงวนไว้สำหรับการนำเข้าในอนาคต
suspend fun processChanges(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 เพื่อ upsert ระเบียน
สำหรับ DeletionChange ให้ใช้ id ที่ระบุเพื่อลบระเบียน
โดยคุณจะต้องจัดเก็บระเบียน id ตามที่ระบุไว้ใน
จัดเก็บรหัส Health Connect
ลบข้อมูลออกจาก Health Connect
เมื่อผู้ใช้ลบข้อมูลของตนเองออกจากแอปของคุณ โปรดตรวจสอบว่าระบบได้นำข้อมูลดังกล่าวออกจาก Health Connect ด้วย ใช้ deleteRecords
เพื่อดำเนินการนี้ ซึ่งใช้ประเภทระเบียนและรายการค่า id และ clientRecordId
ทำให้สะดวกในการลบข้อมูลหลายรายการพร้อมกัน นอกจากนี้ ยังมีdeleteRecordstimeRangeFilter
อีกด้วย
การซิงค์จากอุปกรณ์ที่สวมใส่ได้ที่มีเวลาในการตอบสนองต่ำ
หากต้องการซิงค์ข้อมูลจากอุปกรณ์ออกกำลังกายแบบสวมใส่ไปยัง 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 บริการนี้
จัดการการเชื่อมต่อกับอุปกรณ์ที่สวมใส่ได้และรับข้อมูลผ่านการเรียกกลับ BLE
GATT เมื่อได้รับข้อมูลใหม่ ระบบจะเขียนข้อมูลดังกล่าวลงใน Health
Connect ทันที
import android.companion.CompanionDeviceService
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothGattCharacteristic
import androidx.health.connect.client.permission.HealthPermission
import androidx.health.connect.client.HealthConnectClient
import androidx.health.connect.client.records.HeartRateRecord
import androidx.health.connect.client.records.StepsRecord
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
class MyWearableService : CompanionDeviceService() {
// A coroutine scope for handling suspend functions like writing to Health Connect
private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private var healthConnectClient: HealthConnectClient? = null
private var bluetoothGatt: BluetoothGatt? = null
// This is called by the system when your wearable connects
override fun onDeviceAppeared(address: String) {
super.onDeviceAppeared(address)
healthConnectClient = HealthConnectClient.getOrCreate(this)
serviceScope.launch {
// Check which permissions have been granted before subscribing to data from the wearable.
// A service cannot request permissions, so your app must have already requested
// and been granted them from an Activity.
val granted = healthConnectClient?.permissionController?.getGrantedPermissions()
// ... set up your GATT connection here ...
// Once connected, subscribe to notifications for the data types you have
// permission to write.
if (granted?.contains(HealthPermission.getWritePermission(HeartRateRecord::class)) == true) {
// subscribeToHeartRate(bluetoothGatt)
}
}
}
// The core of your low-latency pipeline is the BLE callback
private val gattCallback = object : BluetoothGattCallback() {
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray) {
super.onCharacteristicChanged(gatt, characteristic, value)
// 1. Instantly receive the data
val rawData = value
// 2. Parse the data from the wearable
val healthData = parseWearableData(rawData) // Your custom parsing logic
// 3. Immediately process it. For simplicity, this example writes
// directly to Health Connect. A real-world app might write to its
// own datastore first and then sync with Health Connect.
serviceScope.launch {
writeToHealthConnect(healthData)
}
}
}
private suspend fun writeToHealthConnect(healthData: HealthData) {
val records = prepareHealthConnectRecords(healthData) // Convert to Health Connect records
try {
healthConnectClient?.insertRecords(records)
} catch (e: Exception) {
// Handle exceptions
}
}
// This is called by the system when your wearable disconnects
override fun onDeviceDisappeared(address: String) {
super.onDeviceDisappeared(address)
// Clean up your GATT connection and other resources
bluetoothGatt?.close()
}
}
แนวทางปฏิบัติแนะนำสำหรับการซิงค์ข้อมูล
ปัจจัยต่อไปนี้มีผลต่อกระบวนการซิงค์
การหมดอายุของโทเค็น
เนื่องจากโทเค็นการเปลี่ยนแปลงที่ไม่ได้ใช้จะหมดอายุภายใน 30 วัน คุณจึงต้องใช้กลยุทธ์การซิงค์ ที่หลีกเลี่ยงการสูญเสียข้อมูลในกรณีดังกล่าว กลยุทธ์ของคุณอาจ รวมถึงแนวทางต่อไปนี้
- ค้นหาที่เก็บข้อมูลแอปสำหรับบันทึกที่ใช้ล่าสุดซึ่งมี
idจาก Health Connect ด้วย - ขอระเบียนจาก Health Connect ที่เริ่มต้นด้วย การประทับเวลาที่เฉพาะเจาะจง จากนั้นแทรกหรืออัปเดตระเบียนเหล่านั้นใน Datastore ของแอป
- ขอโทเค็นการเปลี่ยนแปลงเพื่อจองไว้สำหรับครั้งถัดไปที่จำเป็น
กลยุทธ์การจัดการการเปลี่ยนแปลงที่แนะนำ
ในกรณีที่แอปได้รับโทเค็นการเปลี่ยนแปลงที่ไม่ถูกต้องหรือหมดอายุ เราขอแนะนำกลยุทธ์การจัดการต่อไปนี้โดยขึ้นอยู่กับการใช้งานในตรรกะของคุณ
- อ่านและขจัดข้อมูลที่ซ้ำกันทั้งหมด นี่เป็นกลยุทธ์ที่เหมาะที่สุด
- จัดเก็บการประทับเวลาของครั้งล่าสุดที่แอปอ่านข้อมูลจาก Health Connect
- เมื่อโทเค็นหมดอายุ ให้อ่านข้อมูลทั้งหมดอีกครั้งจากแสตมป์เวลาล่าสุดหรือในช่วง 30 วันที่ผ่านมา จากนั้นขจัดข้อมูลที่ซ้ำกันกับข้อมูลที่อ่านก่อนหน้านี้โดยใช้ตัวระบุ
- ขอแนะนำให้ติดตั้งใช้งาน Client-ID เนื่องจากจำเป็นสำหรับการอัปเดตข้อมูล
- อ่านเฉพาะข้อมูลตั้งแต่การประทับเวลาการอ่านครั้งล่าสุด ซึ่งจะส่งผลให้ข้อมูลบางอย่างไม่ตรงกันในช่วงเวลาที่โทเค็นการเปลี่ยนแปลงหมดอายุ แต่ระยะเวลาจะสั้นลง โดยอาจใช้เวลา 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 จุดต่อไปนี้
- ทุกครั้งที่แอปของคุณทำงานอยู่เบื้องหน้า ในกรณีนี้ ให้ใช้ เหตุการณ์วงจร
- เป็นระยะๆ ขณะที่แอปยังคงทำงานอยู่เบื้องหน้า แจ้งผู้ใช้เมื่อมีข้อมูลใหม่พร้อมใช้งาน เพื่อให้ผู้ใช้สามารถอัปเดตหน้าจอให้แสดงการเปลี่ยนแปลงได้