Per utilizzare le API del framework Android per i record sanitari personali (PHR), devi:
- Configurare l'ambiente utilizzando Android Studio
- Crea istanza
HealthConnectManager
- Gestire le autorizzazioni
- Creare origini dati
Configurare l'ambiente utilizzando Android Studio
Per poter accedere alle API più recenti, devi disporre anche degli strumenti pertinenti più recenti:
- Installa l'ultima versione di Android Studio.
- In Android Studio, vai a Strumenti > Gestore SDK.
- Nella scheda Piattaforme SDK, seleziona Android Baklava.
- Questa versione include il livello API 36 e le API PHR.
- Nella scheda Strumenti SDK, seleziona gli Android SDK Build-Tools più recenti disponibili.
- Fai clic su OK per installare l'SDK.
- Utilizza la versione più recente disponibile del plug-in Android per Gradle.
Dichiarare i livelli API
Per accedere alle API PHR, devi scegliere come target la versione appropriata di Android. Questo viene fatto dichiarando i livelli API in app/build.gradle
.
...
compileSdk = 36
defaultConfig {
targetSdk = 36
...
Scopri di più sulla configurazione dei livelli API nell'elemento uses-sdk e nella documentazione Configurare l'SDK Android 16.
Dichiarare le autorizzazioni
Aggiungi nuove autorizzazioni per la RPP in AndroidManifest.xml
.
Dichiara le autorizzazioni solo per i tipi di dati che intendi utilizzare nella tua applicazione. L'elenco completo delle autorizzazioni relative alla salute è mostrato nel
blocco di codice. Le autorizzazioni non correlate alla RPD per Connessione Salute non sono incluse.
...
<!-- 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"/>
...
Se un'applicazione tenta di utilizzare un'API che richiede un'autorizzazione e questa autorizzazione non è dichiarata nel file manifest dell'app, verrà generato un SecurityException
.
Per un'eccezione di tipo SecurityException
, sarà disponibile un messaggio di errore utile in exception.localizedMessage
.
Crea un'istanza di HealthConnectManager
HealthConnectManager
è la classe responsabile della gestione delle interazioni con le autorizzazioni, nonché delle letture e delle scritture nel repository dei dati locali di Connessione Salute. Esploreremo i metodi di istanza di HealthConnectManager
nelle sezioni successive. Poiché HealthConnectManager espone un servizio di sistema,
non puoi creare direttamente un'istanza di questa classe e devi utilizzare
getSystemService
.
In particolare, tieni presente che il servizio di sistema è strettamente associato al contesto in cui viene creato e non deve essere reso accessibile al di fuori di questo contesto.
import android.health.connect.HealthConnectManager
...
val healthConnectManager: HealthConnectManager = requireNotNull(applicationContext.getSystemService(HealthConnectManager::class.java))
Gestire le autorizzazioni
L'utente della tua app deve concederle l'autorizzazione ad accedere ai dati di Connessione Salute. A tale scopo, avvia una nuova attività con le autorizzazioni specificate e utilizza l'elenco risultante delle autorizzazioni concesse. L'interfaccia utente della nuova attività consentirà all'utente di selezionare le autorizzazioni di cui ha bisogno per concedere la tua app. Richiedi le autorizzazioni solo per i tipi di dati che intendi utilizzare nella tua applicazione.
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)
Il tentativo di leggere o scrivere senza un'autorizzazione richiesta comporterà un HealthConnectException
.
Per un'eccezione di tipo HealthConnectException
, sarà disponibile un messaggio di errore utile in exception.localizedMessage
.
Creare origini dati
Per scrivere dati sanitari in Connessione Salute, la tua applicazione deve prima creare un'origine dati per contenere le informazioni. Un'origine dati in genere rappresenta un sistema medico o un'API particolare.
Nell'esempio, creiamo un'origine dati denominata My Hospital
e specifichiamo la versione 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"),
)
Scrivere record
Prepara record FHIR di esempio in JSON. Sul web sono disponibili varie fonti con dati di esempio in formato 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"
}
}
]
}
Inserisci i dati:
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
prende come argomento un elenco di
UpsertMedicalResourceRequest
. Se non è possibile inserire un singolo UpsertMedicalResourceRequest
tramesso nella chiamata, non verrà eseguito alcun commit nel
repository per l'intero elenco di UpsertMedicalResourceRequest
.
Se una richiesta contiene ID MedicalDataSource
non validi, l'API restituirà un
IllegalArgumentException
. Se una richiesta viene considerata non valida per altri motivi, il chiamante riceverà un HealthConnectException
.
La chiave univoca per una determinata richiesta è la combinazione di ID origine dati, tipo di risorsa FHIR e ID risorsa FHIR. Se questi tre elementi di una richiesta corrispondenti a un record esistente, viene attivato un aggiornamento. In caso contrario, viene creato un nuovo record.
Leggere i record
Leggi i record per tipo, quindi gestisci i risultati come preferisci.
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
}