Управляйте ресурсами FHIR с помощью библиотеки FHIR Engine.

1. Прежде чем начать

Что ты построишь

В этой лаборатории кода вы создадите приложение для Android с использованием библиотеки FHIR Engine. Ваше приложение будет использовать библиотеку FHIR Engine для загрузки ресурсов FHIR с сервера FHIR и загрузки любых локальных изменений на сервер.

Что вы узнаете

  • Как создать локальный сервер HAPI FHIR с помощью Docker
  • Как интегрировать библиотеку FHIR Engine в ваше приложение для Android
  • Как использовать API синхронизации для настройки однократного или периодического задания по загрузке и отправке ресурсов FHIR.
  • Как использовать API поиска
  • Как использовать API-интерфейсы доступа к данным для локального создания, чтения, обновления и удаления ресурсов FHIR.

Что вам понадобится

Если вы раньше не создавали приложения для Android, вы можете начать с создания своего первого приложения .

2. Настройте локальный сервер HAPI FHIR с тестовыми данными.

HAPI FHIR — популярный сервер FHIR с открытым исходным кодом. В нашей лаборатории кода мы используем локальный сервер HAPI FHIR, к которому может подключаться приложение Android.

Настройте локальный сервер HAPI FHIR.

  1. Запустите следующую команду в терминале, чтобы получить последний образ HAPI FHIR.
    docker pull hapiproject/hapi:latest
    
  2. Создайте контейнер HAPI FHIR, используя Docker Desktop для запуска ранее загруженного образа hapiproject/hapi или выполнив следующую команду.
    docker run -p 8080:8080 hapiproject/hapi:latest
    
    Узнать больше .
  3. Проверьте сервер, открыв URL-адрес http://localhost:8080/ в браузере. Вы должны увидеть веб-интерфейс HAPI FHIR. HAPI FHIR web interface

Заполнение локального сервера HAPI FHIR тестовыми данными.

Чтобы протестировать наше приложение, нам понадобятся некоторые тестовые данные на сервере. Мы будем использовать синтетические данные, сгенерированные Synthea.

  1. Во-первых, нам нужно загрузить образцы данных из Synthea-samples . Загрузите и распакуйте synthea_sample_data_fhir_r4_sep2019.zip . Разархивированные образцы данных содержат множество файлов .json , каждый из которых представляет собой пакет транзакций для отдельного пациента.
  2. Мы загрузим данные тестов трех пациентов на локальный сервер HAPI FHIR. Запустите следующую команду в каталоге, содержащем файлы JSON.
    curl -X POST -H "Content-Type: application/json" -d @./Aaron697_Brekke496_2fa15bc7-8866-461a-9000-f739e425860a.json http://localhost:8080/fhir/
    curl -X POST -H "Content-Type: application/json" -d @./Aaron697_Stiedemann542_41166989-975d-4d17-b9de-17f94cb3eec1.json http://localhost:8080/fhir/
    curl -X POST -H "Content-Type: application/json" -d @./Abby752_Kuvalis369_2b083021-e93f-4991-bf49-fd4f20060ef8.json http://localhost:8080/fhir/
    
  3. Чтобы загрузить данные тестов для всех пациентов на сервер, запустите
    for f in *.json; do curl -X POST -H "Content-Type: application/json" -d @$f http://localhost:8080/fhir/ ; done
    
    Однако это может занять много времени и не является необходимым для лаборатории разработки кода.
  4. Убедитесь, что тестовые данные доступны на сервере, открыв URL-адрес http://localhost:8080/fhir/Patient/ в браузере. В качестве результата поиска с total количеством вы должны увидеть текст HTTP 200 OK и раздел Response Body на странице, содержащей данные пациента в пакете FHIR. Test data on server

3. Установите приложение для Android.

Загрузите код

Чтобы загрузить код для этой лаборатории, клонируйте репозиторий Android FHIR SDK: git clone https://github.com/google/android-fhir.git

Стартовый проект для этой лаборатории находится в codelabs/engine .

Импортируйте приложение в Android Studio.

Начнем с импорта стартового приложения в Android Studio.

Откройте Android Studio, выберите «Импортировать проект» (Gradle, Eclipse ADT и т. д.) и выберите папку codelabs/engine/ из исходного кода, который вы загрузили ранее.

Android Studio start screen

Синхронизируйте свой проект с файлами Gradle.

Для вашего удобства в проект уже добавлены зависимости библиотеки FHIR Engine. Это позволяет вам интегрировать библиотеку FHIR Engine в ваше приложение. Обратите внимание на следующие строки в конце файла app/build.gradle.kts вашего проекта:

dependencies {
    // ...

    implementation("com.google.android.fhir:engine:0.1.0-beta05")
}

Чтобы быть уверенным, что все зависимости доступны для вашего приложения, на этом этапе вам следует синхронизировать свой проект с файлами Gradle.

Выберите «Синхронизировать проект с файлами Gradle » ( Gradle sync button ) на панели инструментов Android Studio. Вы также можете снова запустить приложение, чтобы проверить правильность работы зависимостей.

Запустите стартовое приложение

Теперь, когда вы импортировали проект в Android Studio, вы готовы впервые запустить приложение.

Запустите эмулятор Android Studio и нажмите «Выполнить» ( Run button ) на панели инструментов Android Studio.

Приложение Привет, мир

4. Создайте экземпляр FHIR Engine.

Чтобы включить механизм FHIR Engine в ваше приложение для Android, вам необходимо использовать библиотеку FHIR Engine и запустить экземпляр FHIR Engine. Шаги, описанные ниже, помогут вам в этом процессе.

  1. Перейдите к классу приложения (в данном примере это FhirApplication.kt , расположенному в app/src/main/java/com/google/android/fhir/codelabs/engine .
  2. Внутри метода onCreate() добавьте следующий код для инициализации FHIR Engine:
      FhirEngineProvider.init(
          FhirEngineConfiguration(
            enableEncryptionIfSupported = true,
            RECREATE_AT_OPEN,
            ServerConfiguration(
              baseUrl = "http://10.0.2.2:8080/fhir/",
              httpLogger =
                HttpLogger(
                  HttpLogger.Configuration(
                    if (BuildConfig.DEBUG) HttpLogger.Level.BODY else HttpLogger.Level.BASIC,
                  ),
                ) {
                  Log.d("App-HttpLog", it)
                },
            ),
          ),
      )
    
    Примечания:
    • enableEncryptionIfSupported : включает шифрование данных, если устройство его поддерживает.
    • RECREATE_AT_OPEN : определяет стратегию ошибок базы данных. В этом случае он пересоздает базу данных, если при открытии возникает ошибка.
    • baseUrl в ServerConfiguration : это базовый URL-адрес сервера FHIR. Предоставленный IP-адрес 10.0.2.2 специально зарезервирован для локального хоста, доступного из эмулятора Android. Узнать больше .
  3. В классе FhirApplication добавьте следующую строку для ленивого создания экземпляра механизма FHIR:
      private val fhirEngine: FhirEngine by
          lazy { FhirEngineProvider.getInstance(this) }
    
    Это гарантирует, что экземпляр FhirEngine будет создан только при первом доступе к нему, а не сразу при запуске приложения.
  4. Добавьте следующий удобный метод в класс FhirApplication для облегчения доступа ко всему приложению:
    companion object {
        fun fhirEngine(context: Context) =
            (context.applicationContext as FhirApplication).fhirEngine
    }
    
    Этот статический метод позволяет получить экземпляр FHIR Engine из любого места приложения, используя контекст.

5. Синхронизировать данные с сервером FHIR.

  1. Создайте новый класс DownloadWorkManagerImpl.kt . В этом классе вы определите, как приложение извлекает следующий ресурс из списка для загрузки:
      class DownloadWorkManagerImpl : DownloadWorkManager {
        private val urls = LinkedList(listOf("Patient"))
    
        override suspend fun getNextRequest(): DownloadRequest? {
          val url = urls.poll() ?: return null
          return DownloadRequest.of(url)
        }
    
        override suspend fun getSummaryRequestUrls() = mapOf<ResourceType, String>()
    
        override suspend fun processResponse(response: Resource): Collection<Resource> {
          var bundleCollection: Collection<Resource> = mutableListOf()
          if (response is Bundle && response.type == Bundle.BundleType.SEARCHSET) {
            bundleCollection = response.entry.map { it.resource }
          }
          return bundleCollection
        }
      }
    
    У этого класса есть очередь типов ресурсов, которые он хочет загрузить. Он обрабатывает ответы и извлекает ресурсы из возвращенного пакета, которые сохраняются в локальной базе данных.
  2. Создайте новый класс AppFhirSyncWorker.kt Этот класс определяет, как приложение будет синхронизироваться с удаленным сервером FHIR с использованием фонового рабочего процесса.
    class AppFhirSyncWorker(appContext: Context, workerParams: WorkerParameters) :
      FhirSyncWorker(appContext, workerParams) {
    
      override fun getDownloadWorkManager() = DownloadWorkManagerImpl()
    
      override fun getConflictResolver() = AcceptLocalConflictResolver
    
      override fun getFhirEngine() = FhirApplication.fhirEngine(applicationContext)
    }
    
    Здесь мы определили, какой диспетчер загрузки, средство разрешения конфликтов и экземпляр механизма FHIR использовать для синхронизации.
  3. В вашей ViewModel PatientListViewModel.kt вы настроите механизм однократной синхронизации. Найдите и добавьте этот код в функцию triggerOneTimeSync() :
    viewModelScope.launch {
          Sync.oneTimeSync<AppFhirSyncWorker>(getApplication())
            .shareIn(this, SharingStarted.Eagerly, 10)
            .collect { _pollState.emit(it) }
        }
    
    Эта сопрограмма инициирует однократную синхронизацию с сервером FHIR, используя AppFhirSyncWorker, который мы определили ранее. Затем он обновит пользовательский интерфейс в зависимости от состояния процесса синхронизации.
  4. В файле PatientListFragment.kt обновите тело функции handleSyncJobStatus :
    when (syncJobStatus) {
        is SyncJobStatus.Finished -> {
            Toast.makeText(requireContext(), "Sync Finished", Toast.LENGTH_SHORT).show()
            viewModel.searchPatientsByName("")
        }
        else -> {}
    }
    
    Здесь, когда процесс синхронизации завершится, появится всплывающее сообщение, уведомляющее пользователя, а затем приложение отобразит всех пациентов, вызвав поиск с пустым именем.

Теперь, когда все настроено, запустите приложение. Нажмите кнопку Sync в меню. Если все работает правильно, вы должны увидеть, как пациенты с вашего локального сервера FHIR загружаются и отображаются в приложении.

Список пациентов

6. Изменить и загрузить данные пациента

В этом разделе мы покажем вам процесс изменения данных пациента на основе определенных критериев и загрузки обновленных данных на ваш сервер FHIR. В частности, мы поменяем адреса городов для пациентов, проживающих в Wakefield и Taunton .

Шаг 1. Настройте логику изменения в PatientListViewModel.

Код в этом разделе добавляется в функцию triggerUpdate в PatientListViewModel

  1. Доступ к механизму FHIR . Начните с получения ссылки на механизм FHIR в PatientListViewModel.kt .
    viewModelScope.launch {
       val fhirEngine = FhirApplication.fhirEngine(getApplication())
    
    Этот код запускает сопрограмму в области ViewModel и инициализирует механизм FHIR.
  2. Поиск пациентов из Уэйкфилда : Используйте систему FHIR для поиска пациентов с адресом в городе Wakefield .
    val patientsFromWakefield =
         fhirEngine.search<Patient> {
           filter(
             Patient.ADDRESS_CITY,
             {
               modifier =  StringFilterModifier.MATCHES_EXACTLY
               value = "Wakefield"
             }
           )
         }
    
    Здесь мы используем метод search системы FHIR для фильтрации пациентов по городу их адреса. Результатом будет список пациентов из Уэйкфилда.
  3. Поиск пациентов из Тонтона : Аналогичным образом осуществляется поиск пациентов с адресом в городе Taunton .
    val patientsFromTaunton =
         fhirEngine.search<Patient> {
           filter(
             Patient.ADDRESS_CITY,
             {
               modifier =  StringFilterModifier.MATCHES_EXACTLY
               value = "Taunton"
             }
           )
         }
    
    Теперь у нас есть два списка пациентов — один из Уэйкфилда, другой из Тонтона.
  4. Измените адреса пациентов : просмотрите каждого пациента в списке patientsFromWakefield , измените его город на Taunton и обновите их в механизме FHIR.
    patientsFromWakefield.forEach {
         it.resource.address.first().city = "Taunton"
         fhirEngine.update(it.resource)
    }
    
    Аналогичным образом обновите каждого пациента в списке patientsFromTaunton , чтобы изменить его город на Wakefield .
    patientsFromTaunton.forEach {
         it.resource.address.first().city = "Wakefield"
         fhirEngine.update(it.resource)
    }
    
  5. Начать синхронизацию : после локального изменения данных запустите однократную синхронизацию, чтобы гарантировать обновление данных на сервере FHIR.
    triggerOneTimeSync()
    }
    
    Закрывающая скобка } означает конец сопрограммы, запущенной в начале.

Шаг 2 : Проверьте функциональность

  1. Тестирование пользовательского интерфейса : запустите приложение. Нажмите кнопку Update в меню. Вы должны увидеть, что адреса городов для пациентов Aaron697 и Abby752 поменялись местами.
  2. Проверка сервера : откройте браузер и перейдите по адресу http://localhost:8080/fhir/Patient/ . Убедитесь, что адрес города для пациентов Aaron697 и Abby752 обновлен на локальном сервере FHIR.

Выполнив эти шаги, вы успешно внедрили механизм изменения данных пациента и синхронизировали изменения с вашим сервером FHIR.

7. Поиск пациентов по имени

Поиск пациентов по именам может обеспечить удобный способ получения информации. Здесь мы покажем вам процесс реализации этой функции в вашем приложении.

Шаг 1. Обновите сигнатуру функции.

Перейдите к файлу PatientListViewModel.kt и найдите функцию с именем searchPatientsByName . Мы добавим код в эту функцию.

Чтобы отфильтровать результаты на основе предоставленного запроса имени и передать результаты для обновления пользовательского интерфейса, включите следующий блок условного кода:

    viewModelScope.launch {
      val fhirEngine = FhirApplication.fhirEngine(getApplication())
      if (nameQuery.isNotEmpty()) {
        val searchResult = fhirEngine.search<Patient> {
          filter(
            Patient.NAME,
            {
              modifier = StringFilterModifier.CONTAINS
              value = nameQuery
            },
          )
        }
        liveSearchedPatients.value  =  searchResult.map { it.resource }
      }
    }

Здесь, если nameQuery не пуст, функция поиска будет фильтровать результаты, чтобы включать только пациентов, имена которых содержат указанный запрос.

Шаг 2. Проверьте новую функцию поиска.

  1. Перезапустите приложение . После внесения этих изменений пересоберите и запустите приложение.
  2. Поиск пациентов : на экране списка пациентов используйте функцию поиска. Теперь вы сможете ввести имя (или часть имени), чтобы соответствующим образом отфильтровать список пациентов.

Выполнив эти шаги, вы усовершенствовали свое приложение, предоставив пользователям возможность эффективно искать пациентов по их именам. Это может значительно улучшить взаимодействие с пользователем и повысить эффективность поиска данных.

8. Поздравляем!

Вы использовали библиотеку FHIR Engine для управления ресурсами FHIR в своем приложении:

  • Используйте API синхронизации для синхронизации ресурсов FHIR с сервером FHIR.
  • Используйте API доступа к данным для создания, чтения, обновления и удаления локальных ресурсов FHIR.
  • Используйте API поиска для поиска местных ресурсов FHIR.

Что мы рассмотрели

  • Как настроить локальный сервер HAPI FHIR
  • Как загрузить тестовые данные на локальный сервер HAPI FHIR
  • Как создать приложение для Android с помощью библиотеки FHIR Engine
  • Как использовать API синхронизации, API доступа к данным и API поиска в библиотеке FHIR Engine.

Следующие шаги

  • Изучите документацию по библиотеке FHIR Engine.
  • Ознакомьтесь с расширенными функциями API поиска.
  • Примените библиотеку FHIR Engine в своем собственном приложении для Android.

Узнать больше