หากต้องการใช้ API ของเฟรมเวิร์ก Android สําหรับบันทึกสุขภาพส่วนตัว (PHR) คุณต้องมีคุณสมบัติดังนี้
- กำหนดค่าสภาพแวดล้อมโดยใช้ Android Studio
- สร้างอินสแตนซ์
HealthConnectManager
- จัดการสิทธิ์
- สร้างแหล่งข้อมูล
กำหนดค่าสภาพแวดล้อมโดยใช้ Android Studio
หากต้องการเข้าถึง API เวอร์ชันล่าสุด คุณต้องมีสิทธิ์เข้าถึงเครื่องมือที่เกี่ยวข้องเวอร์ชันล่าสุดด้วย
- ติดตั้ง Android Studio เวอร์ชันล่าสุด
- ใน Android Studio ให้ไปที่เครื่องมือ > เครื่องมือจัดการ SDK
- ในแท็บแพลตฟอร์ม SDK ให้เลือก Android Baklava
- เวอร์ชันนี้รวม API ระดับ 36 และ PHR API
- ในแท็บเครื่องมือ SDK ให้เลือก Android SDK Build-Tools เวอร์ชันล่าสุดที่ใช้ได้
- คลิก "ตกลง" เพื่อติดตั้ง SDK
- ใช้ปลั๊กอิน Android Gradle เวอร์ชันล่าสุดที่มี
ประกาศระดับ API
หากต้องการเข้าถึง PHR API คุณจะต้องกำหนดเป้าหมาย Android เวอร์ชันที่เหมาะสม ซึ่งทำได้โดยการประกาศระดับ API ใน app/build.gradle
...
compileSdk = 36
defaultConfig {
targetSdk = 36
...
ดูข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดค่าระดับ API ในเอกสารประกอบองค์ประกอบ uses-sdk และตั้งค่า SDK ของ Android 16
ประกาศสิทธิ์
เพิ่มสิทธิ์ PHR ใหม่ใน AndroidManifest.xml
ประกาศสิทธิ์สําหรับประเภทข้อมูลที่คุณต้องการใช้ในแอปพลิเคชันเท่านั้น รายการสิทธิ์ทั้งหมดที่เกี่ยวข้องกับทางการแพทย์จะแสดงในบล็อกโค้ด โดยไม่รวมสิทธิ์ที่ไม่เกี่ยวข้องกับ PHR สำหรับ Health Connect
...
<!-- Medical permissions -->
<uses-permission android:name="android.permission.health.WRITE_MEDICAL_DATA"/>
<uses-permission android:name="android.permission.health.READ_MEDICAL_DATA_ALLERGIES_INTOLERANCES"/>
<uses-permission android:name="android.permission.health.READ_MEDICAL_DATA_CONDITIONS"/>
<uses-permission android:name="android.permission.health.READ_MEDICAL_DATA_IMMUNIZATIONS"/>
<uses-permission android:name="android.permission.health.READ_MEDICAL_DATA_LABORATORY_RESULTS"/>
<uses-permission android:name="android.permission.health.READ_MEDICAL_DATA_MEDICATIONS"/>
<uses-permission android:name="android.permission.health.READ_MEDICAL_DATA_PERSONAL_DETAILS"/>
<uses-permission android:name="android.permission.health.READ_MEDICAL_DATA_PRACTITIONER_DETAILS"/>
<uses-permission android:name="android.permission.health.READ_MEDICAL_DATA_PREGNANCY"/>
<uses-permission android:name="android.permission.health.READ_MEDICAL_DATA_PROCEDURES"/>
<uses-permission android:name="android.permission.health.READ_MEDICAL_DATA_SOCIAL_HISTORY"/>
<uses-permission android:name="android.permission.health.READ_MEDICAL_DATA_VISITS"/>
<uses-permission android:name="android.permission.health.READ_MEDICAL_DATA_VITAL_SIGNS"/>
...
หากแอปพลิเคชันพยายามใช้ API ที่ต้องใช้สิทธิ์ และไม่ได้ประกาศสิทธิ์นั้นในไฟล์ Manifest ของแอป ระบบจะแสดงข้อผิดพลาด SecurityException
สําหรับข้อยกเว้นประเภท SecurityException
ข้อความแสดงข้อผิดพลาดที่เป็นประโยชน์จะแสดงใน exception.localizedMessage
สร้าง HealthConnectManager
HealthConnectManager
เป็นคลาสที่รับผิดชอบการจัดการการโต้ตอบเกี่ยวกับสิทธิ์ รวมถึงการอ่านและเขียนไปยังที่เก็บข้อมูลในเครื่องของ Health Connect เราจะสำรวจเมธอดอินสแตนซ์ของ HealthConnectManager
ในส่วนถัดไป เนื่องจาก HealthConnectManager แสดงบริการของระบบ คุณจึงไม่สามารถสร้างอินสแตนซ์ของคลาสนี้โดยตรง และต้องใช้ getSystemService
โดยเฉพาะอย่างยิ่ง โปรดทราบว่าบริการของระบบจะเชื่อมโยงกับบริบทที่สร้างขึ้นอย่างแน่นหนา และไม่ควรทำให้เข้าถึงได้นอกบริบทนั้น
import android.health.connect.HealthConnectManager
...
val healthConnectManager: HealthConnectManager = requireNotNull(applicationContext.getSystemService(HealthConnectManager::class.java))
จัดการสิทธิ์
ผู้ใช้แอปพลิเคชันต้องให้สิทธิ์แอปพลิเคชันในการเข้าถึงข้อมูล Health Connect โดยให้เปิดใช้งานกิจกรรมใหม่ที่มีสิทธิ์ที่ระบุไว้ แล้วใช้รายการสิทธิ์ที่ได้รับ UI ของกิจกรรมใหม่จะอนุญาตให้ผู้ใช้เลือกสิทธิ์ที่ต้องการมอบให้แอปของคุณ ขอสิทธิ์สำหรับประเภทข้อมูลที่คุณต้องการให้แอปพลิเคชันใช้เท่านั้น
val MEDICAL_PERMISSIONS = arrayOf(
"android.permission.health.READ_MEDICAL_DATA_ALLERGIES_INTOLERANCES",
"android.permission.health.READ_MEDICAL_DATA_CONDITIONS",
"android.permission.health.READ_MEDICAL_DATA_IMMUNIZATIONS",
"android.permission.health.READ_MEDICAL_DATA_LABORATORY_RESULTS",
"android.permission.health.READ_MEDICAL_DATA_MEDICATIONS",
"android.permission.health.READ_MEDICAL_DATA_PERSONAL_DETAILS",
"android.permission.health.READ_MEDICAL_DATA_PRACTITIONER_DETAILS",
"android.permission.health.READ_MEDICAL_DATA_PREGNANCY",
"android.permission.health.READ_MEDICAL_DATA_PROCEDURES",
"android.permission.health.READ_MEDICAL_DATA_SOCIAL_HISTORY",
"android.permission.health.READ_MEDICAL_DATA_VISITS",
"android.permission.health.READ_MEDICAL_DATA_VITAL_SIGNS",
"android.permission.health.WRITE_MEDICAL_DATA",
)
...
private lateinit var mRequestPermissionLauncher: ActivityResultLauncher<Array<String>>
...
mRequestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
permissionMap: Map<String, Boolean> ->
requestPermissionResultHandler(permissionMap)
}
}
...
private fun requestPermissionResultHandler(permissionMap: Map<String, Boolean>) {
// Evaluate permissionMap and handle any missing permissions
}
...
mRequestPermissionLauncher.launch(MEDICAL_PERMISSIONS)
การพยายามอ่านหรือเขียนโดยไม่มีสิทธิ์ที่จำเป็นจะส่งผลให้เกิด HealthConnectException
สําหรับข้อยกเว้นประเภท HealthConnectException
ข้อความแสดงข้อผิดพลาดที่เป็นประโยชน์จะแสดงใน exception.localizedMessage
สร้างแหล่งข้อมูล
หากต้องการเขียนข้อมูลสุขภาพลงใน Health Connect แอปพลิเคชันของคุณจะต้องสร้างแหล่งข้อมูลเพื่อเก็บข้อมูลก่อน โดยทั่วไปแหล่งข้อมูลจะแสดง API หรือระบบทางการแพทย์ที่เฉพาะเจาะจง
ในตัวอย่างนี้ เราสร้างแหล่งข้อมูลชื่อ My Hospital
และระบุเวอร์ชัน FHIR
import android.health.connect.CreateMedicalDataSourceRequest
import android.health.connect.HealthConnectManager
import android.health.connect.datatypes.FhirVersion
import android.health.connect.datatypes.MedicalDataSource
import android.net.Uri
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.os.asOutcomeReceiver
import kotlinx.coroutines.suspendCancellableCoroutine
...
private suspend fun createMedicalDataSource(
fhirBaseUri: Uri,
displayName: String,
fhirVersion: FhirVersion,
): String {
val dataSource =
suspendCancellableCoroutine<MedicalDataSource> { continuation ->
healthConnectManager.createMedicalDataSource(
CreateMedicalDataSourceRequest.Builder(fhirBaseUri,
displayName,
fhirVersion).build(),
Runnable::run,
continuation.asOutcomeReceiver(),
)
}
Log.d("CREATE_DATA_SOURCE", "Created source: $dataSource")
return "Created data source: $displayName"
}
...
createMedicalDataSource(
Uri.parse("example.fhir.com/R4/123"),
"My Hospital",
FhirVersion.parseFhirVersion("4.0.1"),
)
เขียนระเบียน
เตรียมตัวอย่างระเบียน FHIR ใน JSON แหล่งข้อมูลต่างๆ บนเว็บมีตัวอย่างข้อมูลในรูปแบบ FHIR
{
"resourceType": "Immunization",
"id": "immunization-1",
"status": "completed",
"vaccineCode": {
"coding": [
{
"system": "http://hl7.org/fhir/sid/cvx",
"code": "115"
},
{
"system": "http://hl7.org/fhir/sid/ndc",
"code": "58160-842-11"
}
],
"text": "Tdap"
},
"patient": {
"reference": "Patient/patient_1",
"display": "Example, Anne"
},
"encounter": {
"reference": "Encounter/encounter_unk",
"display": "GP Visit"
},
"occurrenceDateTime": "2018-05-21",
"primarySource": true,
"manufacturer": {
"display": "Sanofi Pasteur"
},
"lotNumber": "1",
"site": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v3-ActSite",
"code": "LA",
"display": "Left Arm"
}
],
"text": "Left Arm"
},
"route": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v3-RouteOfAdministration",
"code": "IM",
"display": "Injection, intramuscular"
}
],
"text": "Injection, intramuscular"
},
"doseQuantity": {
"value": 0.5,
"unit": "mL"
},
"performer": [
{
"function": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v2-0443",
"code": "AP",
"display": "Administering Provider"
}
],
"text": "Administering Provider"
},
"actor": {
"reference": "Practitioner/practitioner_1",
"type": "Practitioner",
"display": "Dr Maria Hernandez"
}
}
]
}
แทรกข้อมูล
import android.health.connect.UpsertMedicalResourceRequest
import android.health.connect.datatypes.MedicalResource
...
private suspend fun loadJSONFromAsset(assetName: String): String {
...
private suspend fun upsertMedicalResources(
requests: List<UpsertMedicalResourceRequest>
): List<MedicalResource> {
Log.d("UPSERT_RESOURCES", "Writing ${requests.size} resources")
val resources =
suspendCancellableCoroutine<List<MedicalResource>> { continuation ->
healthConnectManager.upsertMedicalResources(
requests,
Runnable::run,
continuation.asOutcomeReceiver(),
)
}
Log.d("UPSERT_RESOURCES", "Wrote ${resources.size} resources")
return resources
}
...
private suspend fun insertResource(insertedDataSourceId: String, resource: String): String {
val insertedResources =
upsertMedicalResources(
listOf(
UpsertMedicalResourceRequest.Builder(
insertedDataSourceId,
FhirVersion.parseFhirVersion("4.0.1"),
resource,
)
.build()
)
)
return insertedResources.joinToString(
separator = "\n",
transform = MedicalResource::toString,
)
}
...
val immunizationResource =
loadJSONFromAsset("immunization_1.json")
insertResource(dataSource.id, immunizationResource)
upsertMedicalResources
ใช้อาร์กิวเมนต์เป็นลิสต์ของ
UpsertMedicalResourceRequest
หากแทรก UpsertMedicalResourceRequest
รายการใดรายการหนึ่งซึ่งส่งมาในคอลไม่สำเร็จ ระบบจะไม่บันทึกรายการ UpsertMedicalResourceRequest
ทั้งหมดลงในที่เก็บ
หากคำขอใดมีรหัส MedicalDataSource
ที่ไม่ถูกต้อง API จะแสดงIllegalArgumentException
หากคำขอใดก็ตามถือว่าไม่ถูกต้องเนื่องจากเหตุผลอื่นๆ ผู้โทรจะได้รับ HealthConnectException
คีย์ที่ไม่ซ้ำกันของคำขอหนึ่งๆ คือชุดค่าผสมของรหัสแหล่งข้อมูล ประเภททรัพยากร FHIR และรหัสทรัพยากร FHIR หากรายการทั้ง 3 รายการในคำขอตรงกับระเบียนที่มีอยู่ ระบบจะทริกเกอร์การอัปเดต มิเช่นนั้น ระบบจะสร้างระเบียนใหม่
อ่านระเบียน
อ่านระเบียนตามประเภท แล้วจัดการผลลัพธ์ตามที่เห็นสมควร
import android.health.connect.ReadMedicalResourcesInitialRequest
import android.health.connect.ReadMedicalResourcesResponse
import android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_IMMUNIZATIONS
...
private suspend fun readImmunization(): List<MedicalResource> {
var receiver: OutcomeReceiver<ReadMedicalResourcesResponse, HealthConnectException>
val request: ReadMedicalResourcesInitialRequest =
ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_IMMUNIZATIONS).build()
val resources =
suspendCancellableCoroutine<ReadMedicalResourcesResponse> { continuation ->
receiver = continuation.asOutcomeReceiver()
healthConnectManager.readMedicalResources(request, Runnable::run, receiver)
}
.medicalResources
Log.d("READ_MEDICAL_RESOURCES", "Read ${resources.size} resources")
return resources
}