Untuk menggunakan API framework Android untuk Personal Health Records (PHR), Anda harus:
- Mengonfigurasi lingkungan menggunakan Android Studio
- Membuat instance
HealthConnectManager
- Menangani izin
- Membuat sumber data
Mengonfigurasi lingkungan menggunakan Android Studio
Untuk memiliki akses ke API terbaru, Anda juga memerlukan akses ke alat terbaru yang relevan:
- Instal Android Studio versi terbaru.
- Di Android Studio, buka Tools > SDK Manager.
- Di tab SDK Platforms, pilih Android Baklava.
- Versi ini mencakup API level 36 dan PHR API.
- Di tab SDK Tools, pilih Android SDK Build-Tools terbaru yang tersedia.
- Klik OK untuk menginstal SDK.
- Gunakan versi terbaru plugin Android Gradle yang tersedia.
Mendeklarasikan level API
Untuk mengakses PHR API, Anda harus menargetkan versi Android
yang sesuai. Hal ini dilakukan dengan mendeklarasikan API level di app/build.gradle
.
...
compileSdk = 36
defaultConfig {
targetSdk = 36
...
Pelajari lebih lanjut cara mengonfigurasi API level dalam dokumentasi elemen uses-sdk dan Menyiapkan SDK Android 16.
Mendeklarasikan Izin
Tambahkan izin PHR baru di AndroidManifest.xml
.
Deklarasikan izin hanya untuk jenis data yang ingin Anda gunakan dalam
aplikasi. Daftar lengkap izin terkait medis ditampilkan di
blok kode. Izin non-terkait PHR untuk Health Connect tidak disertakan.
...
<!-- 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"/>
...
Jika aplikasi mencoba menggunakan API yang memerlukan izin, dan
izin tersebut tidak dideklarasikan dalam manifes aplikasi, SecurityException
akan ditampilkan.
Untuk pengecualian jenis SecurityException
, pesan error yang berguna akan
tersedia di exception.localizedMessage
.
Membuat instance HealthConnectManager
HealthConnectManager
adalah class yang bertanggung jawab menangani
interaksi izin serta membaca dan menulis ke repositori data lokal
Health Connect. Kita akan mempelajari metode instance HealthConnectManager
di bagian berikutnya. Karena HealthConnectManager mengekspos layanan sistem,
Anda tidak dapat membuat instance class ini secara langsung dan harus menggunakan
getSystemService
.
Secara khusus, perhatikan bahwa layanan sistem digabungkan
dengan erat dengan konteks yang dibuat instance-nya dan tidak boleh
dibuat dapat diakses di luar konteks tersebut.
import android.health.connect.HealthConnectManager
...
val healthConnectManager: HealthConnectManager = requireNotNull(applicationContext.getSystemService(HealthConnectManager::class.java))
Menangani izin
Pengguna aplikasi Anda harus memberikan izin kepada aplikasi Anda untuk mengakses data Health Connect. Untuk melakukannya, luncurkan aktivitas baru dengan izin yang ditentukan, dan gunakan daftar izin yang diberikan. UI aktivitas baru akan memungkinkan pengguna memilih izin yang diperlukan untuk diberikan ke aplikasi Anda. Minta izin hanya untuk jenis data yang ingin digunakan aplikasi Anda.
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)
Mencoba membaca atau menulis tanpa izin yang diperlukan akan menghasilkan
HealthConnectException
.
Untuk pengecualian jenis HealthConnectException
, pesan error yang berguna akan
tersedia di exception.localizedMessage
.
Membuat sumber data
Untuk menulis data kesehatan ke Health Connect, aplikasi Anda harus membuat sumber data terlebih dahulu untuk menyimpan informasi. Sumber data biasanya mewakili API atau sistem medis tertentu.
Dalam contoh, kita membuat sumber data bernama My Hospital
dan menentukan
versi 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"),
)
Menulis data
Siapkan contoh data FHIR dalam JSON. Ada berbagai sumber di seluruh web dengan contoh data dalam format 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"
}
}
]
}
Sisipkan data:
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
menggunakan daftar
UpsertMedicalResourceRequest
sebagai argumen. Jika setiap UpsertMedicalResourceRequest
individual
yang diteruskan dalam panggilan gagal disisipkan, tidak ada operasi tulis yang akan di-commit ke
repositori untuk seluruh daftar UpsertMedicalResourceRequest
.
Jika permintaan berisi ID MedicalDataSource
yang tidak valid, API akan menampilkan
IllegalArgumentException
. Jika permintaan dianggap tidak valid karena alasan
lain, pemanggil akan menerima HealthConnectException
.
Kunci unik untuk permintaan tertentu adalah kombinasi ID sumber data, jenis resource FHIR, dan ID resource FHIR. Jika ketiga item dalam permintaan ini cocok dengan data yang ada, pembaruan akan dipicu. Jika tidak, data baru akan dibuat.
Membaca data
Baca data menurut jenis, lalu tangani hasilnya sesuai keinginan Anda.
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
}