Начало работы с PHR в API платформы Android, Начало работы с PHR в API платформы Android, Начало работы с PHR в API платформы Android, Начало работы с PHR в API платформы Android

Чтобы использовать API платформы Android для личных медицинских записей (PHR), необходимо:

  1. Настройте среду с помощью Android Studio
  2. Создание экземпляра HealthConnectManager
  3. Обработка разрешений
  4. Создание источников данных

Настройте среду с помощью Android Studio

Чтобы иметь доступ к новейшим API, вам также необходим доступ к новейшим соответствующим инструментам:

  • Установите последнюю версию Android Studio .
  • В Android Studio выберите «Инструменты» > «Менеджер SDK» .
    • На вкладке «Платформы SDK» выберите Android Baklava .
    • Эта версия включает API уровня 36 и API PHR.
    • На вкладке «Инструменты SDK» выберите последнюю доступную версию Android SDK Build-Tools .
    • Нажмите «ОК», чтобы установить SDK.
  • Используйте последнюю доступную версию плагина Android Gradle .

Объявить уровни API

Чтобы получить доступ к API PHR, вам необходимо выбрать соответствующую версию Android. Это делается путем объявления уровней API в app/build.gradle .

...
compileSdk = 36

defaultConfig {
  targetSdk = 36
...

Узнайте больше о настройке уровней API в элементе Uses-sdk-element и о настройке документации Android 16 SDK .

Объявить разрешения

Добавьте новые разрешения 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, требующий разрешения, и это разрешение не объявлено в манифесте приложения, будет выдано исключение 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. Для этого запустите новое действие с указанными разрешениями и используйте полученный список предоставленных разрешений. Пользовательский интерфейс нового действия позволит пользователю выбирать разрешения, которые ему необходимо предоставить вашему приложению. Запрашивайте разрешения только для тех типов данных, которые вы планируете использовать в своем приложении.

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. Если эти три элемента в запросе соответствуют существующей записи, запускается обновление. В противном случае создается новая запись.

Чтение записей

Прочитайте записи по типу, а затем обработайте результаты по своему усмотрению.

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
}
,

Чтобы использовать API платформы Android для личных медицинских записей (PHR), необходимо:

  1. Настройте среду с помощью Android Studio
  2. Создание экземпляра HealthConnectManager
  3. Обработка разрешений
  4. Создание источников данных

Настройте среду с помощью Android Studio

Чтобы иметь доступ к новейшим API, вам также необходим доступ к новейшим соответствующим инструментам:

  • Установите последнюю версию Android Studio .
  • В Android Studio выберите «Инструменты» > «Менеджер SDK» .
    • На вкладке «Платформы SDK» выберите Android Baklava .
    • Эта версия включает API уровня 36 и API PHR.
    • На вкладке «Инструменты SDK» выберите последнюю доступную версию Android SDK Build-Tools .
    • Нажмите «ОК», чтобы установить SDK.
  • Используйте последнюю доступную версию плагина Android Gradle .

Объявить уровни API

Чтобы получить доступ к API PHR, вам необходимо выбрать соответствующую версию Android. Это делается путем объявления уровней API в app/build.gradle .

...
compileSdk = 36

defaultConfig {
  targetSdk = 36
...

Узнайте больше о настройке уровней API в элементе Uses-sdk-element и о настройке документации Android 16 SDK .

Объявить разрешения

Добавьте новые разрешения 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, требующий разрешения, и это разрешение не объявлено в манифесте приложения, будет выдано исключение 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. Для этого запустите новое действие с указанными разрешениями и используйте полученный список предоставленных разрешений. Пользовательский интерфейс нового действия позволит пользователю выбирать разрешения, которые ему необходимо предоставить вашему приложению. Запрашивайте разрешения только для тех типов данных, которые вы планируете использовать в своем приложении.

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. Если эти три элемента в запросе соответствуют существующей записи, запускается обновление. В противном случае создается новая запись.

Чтение записей

Прочитайте записи по типу, а затем обработайте результаты по своему усмотрению.

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
}
,

Чтобы использовать API платформы Android для личных медицинских записей (PHR), необходимо:

  1. Настройте среду с помощью Android Studio
  2. Создание экземпляра HealthConnectManager
  3. Обработка разрешений
  4. Создание источников данных

Настройте среду с помощью Android Studio

Чтобы иметь доступ к новейшим API, вам также необходим доступ к новейшим соответствующим инструментам:

  • Установите последнюю версию Android Studio .
  • В Android Studio выберите «Инструменты» > «Менеджер SDK» .
    • На вкладке «Платформы SDK» выберите Android Baklava .
    • Эта версия включает API уровня 36 и API PHR.
    • На вкладке «Инструменты SDK» выберите последнюю доступную версию Android SDK Build-Tools .
    • Нажмите «ОК», чтобы установить SDK.
  • Используйте последнюю доступную версию плагина Android Gradle .

Объявить уровни API

Чтобы получить доступ к API PHR, вам необходимо выбрать соответствующую версию Android. Это делается путем объявления уровней API в app/build.gradle .

...
compileSdk = 36

defaultConfig {
  targetSdk = 36
...

Узнайте больше о настройке уровней API в элементе Uses-sdk-element и о настройке документации Android 16 SDK .

Объявить разрешения

Добавьте новые разрешения 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, требующий разрешения, и это разрешение не объявлено в манифесте приложения, будет выдано исключение 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. Для этого запустите новое действие с указанными разрешениями и используйте полученный список предоставленных разрешений. Пользовательский интерфейс нового действия позволит пользователю выбирать разрешения, которые ему необходимо предоставить вашему приложению. Запрашивайте разрешения только для тех типов данных, которые вы планируете использовать в своем приложении.

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. Если эти три элемента в запросе соответствуют существующей записи, запускается обновление. В противном случае создается новая запись.

Чтение записей

Прочитайте записи по типу, а затем обработайте результаты по своему усмотрению.

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
}
,

Чтобы использовать API платформы Android для личных медицинских записей (PHR), необходимо:

  1. Настройте среду с помощью Android Studio
  2. Создание экземпляра HealthConnectManager
  3. Обработка разрешений
  4. Создание источников данных

Настройте среду с помощью Android Studio

Чтобы иметь доступ к новейшим API, вам также необходим доступ к новейшим соответствующим инструментам:

  • Установите последнюю версию Android Studio .
  • В Android Studio выберите «Инструменты» > «Менеджер SDK» .
    • На вкладке «Платформы SDK» выберите Android Baklava .
    • Эта версия включает API уровня 36 и API PHR.
    • На вкладке «Инструменты SDK» выберите последнюю доступную версию Android SDK Build-Tools .
    • Нажмите «ОК», чтобы установить SDK.
  • Используйте последнюю доступную версию плагина Android Gradle .

Объявить уровни API

Чтобы получить доступ к API PHR, вам необходимо выбрать соответствующую версию Android. Это делается путем объявления уровней API в app/build.gradle .

...
compileSdk = 36

defaultConfig {
  targetSdk = 36
...

Узнайте больше о настройке уровней API в элементе Uses-sdk-element и о настройке документации Android 16 SDK .

Объявить разрешения

Добавьте новые разрешения 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, требующий разрешения, и это разрешение не объявлено в манифесте приложения, будет выдано исключение 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. Для этого запустите новое действие с указанными разрешениями и используйте полученный список предоставленных разрешений. Пользовательский интерфейс нового действия позволит пользователю выбирать разрешения, которые ему необходимо предоставить вашему приложению. Запрашивайте разрешения только для тех типов данных, которые вы планируете использовать в своем приложении.

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. Если эти три элемента в запросе соответствуют существующей записи, запускается обновление. В противном случае создается новая запись.

Чтение записей

Прочитайте записи по типу, а затем обработайте результаты по своему усмотрению.

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
}