FHIR-Ressourcen mit der FHIR-Engine-Bibliothek verwalten

1. Hinweis

Aufgaben

In diesem Codelab erstellen Sie eine Android-App mit der FHIR Engine-Bibliothek. Ihre App verwendet die FHIR Engine-Bibliothek, um FHIR-Ressourcen von einem FHIR-Server herunterzuladen und alle lokalen Änderungen auf den Server hochzuladen.

Lerninhalte

  • Lokalen HAPI FHIR-Server mit Docker erstellen
  • FHIR Engine-Bibliothek in Ihre Android-Anwendung einbinden
  • So richten Sie mit der Sync API einen einmaligen oder regelmäßigen Job zum Herunter- und Hochladen von FHIR-Ressourcen ein
  • Search API verwenden
  • Verwenden der Data Access APIs zum lokalen Erstellen, Lesen, Aktualisieren und Löschen von FHIR-Ressourcen

Voraussetzungen

Wenn Sie noch keine Android-Apps entwickelt haben, können Sie Ihre erste App erstellen.

2. Lokalen HAPI FHIR-Server mit Testdaten einrichten

HAPI FHIR ist ein beliebter Open-Source-FHIR-Server. In unserem Codelab für die Android-App verwenden wir einen lokalen HAPI FHIR-Server, mit dem eine Verbindung hergestellt wird.

Lokalen HAPI FHIR-Server einrichten

  1. Führen Sie den folgenden Befehl in einem Terminal aus, um das aktuelle Image von HAPI FHIR abzurufen:
    docker pull hapiproject/hapi:latest
    
  2. Erstellen Sie einen HAPI FHIR-Container, indem Sie entweder Docker Desktop verwenden, um das zuvor heruntergeladene Image hapiproject/hapi auszuführen, oder den folgenden Befehl ausführen.
    docker run -p 8080:8080 hapiproject/hapi:latest
    
    Weitere Informationen
  3. Sehen Sie sich den Server an, indem Sie die URL http://localhost:8080/ in einem Browser öffnen. Sie sollten die HAPI FHIR-Weboberfläche sehen.HAPI FHIR-Weboberfläche

Lokalen HAPI FHIR-Server mit Testdaten füllen

Um unsere Anwendung zu testen, benötigen wir einige Testdaten auf dem Server. Wir verwenden synthetische Daten, die von Synthea generiert wurden.

  1. Zuerst müssen wir Beispieldaten aus synthea-samples herunterladen. Laden Sie synthea_sample_data_fhir_r4_sep2019.zip herunter und extrahieren Sie die Datei. Die entzippten Beispieldaten enthalten zahlreiche .json-Dateien, die jeweils ein Transaktions-Bundle für einen einzelnen Patienten darstellen.
  2. Wir laden Testdaten für drei Patienten auf den lokalen HAPI FHIR-Server hoch. Führen Sie den folgenden Befehl im Verzeichnis mit den JSON-Dateien aus.
    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. Um Testdaten für alle Patienten auf den Server hochzuladen, führen Sie Folgendes aus:
    for f in *.json; do curl -X POST -H "Content-Type: application/json" -d @$f http://localhost:8080/fhir/ ; done
    
    Dieser Vorgang kann jedoch lange dauern und ist für das Codelab nicht erforderlich.
  4. Prüfen Sie, ob die Testdaten auf dem Server verfügbar sind. Öffnen Sie dazu die URL http://localhost:8080/fhir/Patient/ in einem Browser. Als Suchergebnis sollte der Text HTTP 200 OK und der Abschnitt Response Body der Seite mit Patientendaten in einem FHIR-Bundle mit einer Anzahl von total angezeigt werden.Testdaten auf dem Server

3. Android-App einrichten

Code herunterladen

Wenn Sie den Code für dieses Codelab herunterladen möchten, klonen Sie das Android FHIR SDK-Repository: git clone https://github.com/google/android-fhir.git

Das Starterprojekt für dieses Codelab befindet sich in codelabs/engine.

App in Android Studio importieren

Zuerst importieren wir die Starter-App in Android Studio.

Öffnen Sie Android Studio, wählen Sie Import Project (Gradle, Eclipse ADT, etc.) (Projekt importieren (Gradle, Eclipse ADT usw.)) aus und wählen Sie den Ordner codelabs/engine/ aus dem Quellcode aus, den Sie zuvor heruntergeladen haben.

Android Studio-Startbildschirm

Projekt mit Gradle-Dateien synchronisieren

Die Abhängigkeiten der FHIR Engine-Bibliothek wurden dem Projekt bereits hinzugefügt. So können Sie die FHIR Engine-Bibliothek in Ihre App einbinden. Achten Sie auf die folgenden Zeilen am Ende der app/build.gradle.kts-Datei Ihres Projekts:

dependencies {
    // ...

    implementation("com.google.android.fhir:engine:1.1.0")
}

Damit alle Abhängigkeiten für Ihre App verfügbar sind, sollten Sie Ihr Projekt jetzt mit Gradle-Dateien synchronisieren.

Wählen Sie in der Android Studio-Symbolleiste Sync Project with Gradle Files (Schaltfläche „Gradle-Synchronisierung“) aus. Sie können die App auch noch einmal ausführen, um zu prüfen, ob die Abhängigkeiten richtig funktionieren.

Start-App ausführen

Nachdem Sie das Projekt in Android Studio importiert haben, kann die App zum ersten Mal ausgeführt werden.

Starten Sie den Android Studio-Emulator und klicken Sie in der Android Studio-Symbolleiste auf „Ausführen“ (Schaltfläche „Ausführen“).

Hello World-App

4. FHIR Engine-Instanz erstellen

Wenn Sie die FHIR Engine in Ihre Android-App einbinden möchten, müssen Sie die FHIR Engine-Bibliothek verwenden und eine Instanz der FHIR Engine initiieren. Die folgenden Schritte führen Sie durch den Prozess.

  1. Rufen Sie Ihre Application-Klasse auf, die in diesem Beispiel FhirApplication.kt ist und sich in app/src/main/java/com/google/android/fhir/codelabs/engine befindet.
  2. Fügen Sie in der Methode onCreate() den folgenden Code hinzu, um FHIR Engine zu initialisieren:
      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)
                },
            ),
          ),
      )
    
    Hinweise:
    • enableEncryptionIfSupported: Aktiviert die Datenverschlüsselung, sofern das Gerät sie unterstützt.
    • RECREATE_AT_OPEN: Bestimmt die Strategie für Datenbankfehler. In diesem Fall wird die Datenbank neu erstellt, wenn beim Öffnen ein Fehler auftritt.
    • baseUrl in ServerConfiguration: Dies ist die Basis-URL des FHIR-Servers. Die angegebene IP-Adresse 10.0.2.2 ist speziell für localhost reserviert und kann über den Android-Emulator aufgerufen werden. Weitere Informationen
  3. Fügen Sie in der Klasse FhirApplication die folgende Zeile hinzu, um die FHIR Engine verzögert zu instanziieren:
      private val fhirEngine: FhirEngine by
          lazy { FhirEngineProvider.getInstance(this) }
    
    Dadurch wird sichergestellt, dass die FhirEngine-Instanz erst erstellt wird, wenn zum ersten Mal darauf zugegriffen wird, und nicht sofort beim Start der App.
  4. Fügen Sie der Klasse FhirApplication die folgende Hilfsmethode hinzu, um den Zugriff in Ihrer gesamten Anwendung zu erleichtern:
    companion object {
        fun fhirEngine(context: Context) =
            (context.applicationContext as FhirApplication).fhirEngine
    }
    
    Mit dieser statischen Methode können Sie die FHIR Engine-Instanz mithilfe des Kontextes von überall in der App abrufen.

5. Daten mit FHIR-Server synchronisieren

  1. Erstellen Sie einen neuen Kurs DownloadWorkManagerImpl.kt. In dieser Klasse definieren Sie, wie die Anwendung die nächste Ressource aus der Liste zum Herunterladen abruft:
      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
        }
      }
    
    Diese Klasse hat eine Warteschlange mit Ressourcentypen, die heruntergeladen werden sollen. Es verarbeitet Antworten und extrahiert die Ressourcen aus dem zurückgegebenen Bundle, die in der lokalen Datenbank gespeichert werden.
  2. Erstellen Sie eine neue Klasse AppFhirSyncWorker.kt. Diese Klasse definiert, wie die App mithilfe eines Hintergrund-Workers mit dem Remote-FHIR-Server synchronisiert wird.
    class AppFhirSyncWorker(appContext: Context, workerParams: WorkerParameters) :
      FhirSyncWorker(appContext, workerParams) {
    
      override fun getDownloadWorkManager() = DownloadWorkManagerImpl()
    
      override fun getConflictResolver() = AcceptLocalConflictResolver
    
      override fun getFhirEngine() = FhirApplication.fhirEngine(applicationContext)
    
      override fun getUploadStrategy() =
        UploadStrategy.forBundleRequest(
          methodForCreate = HttpCreateMethod.PUT,
          methodForUpdate = HttpUpdateMethod.PATCH,
          squash = true,
          bundleSize = 500,
        )
    }
    
    Hier haben wir definiert, welcher Downloadmanager, welcher Konfliktlösungsmechanismus und welche FHIR-Engine-Instanz für die Synchronisierung verwendet werden sollen.
  3. In Ihrem ViewModel, PatientListViewModel.kt, richten Sie einen einmaligen Synchronisierungsmechanismus ein. Suchen Sie diesen Code und fügen Sie ihn in die Funktion triggerOneTimeSync() ein:
    viewModelScope.launch {
          Sync.oneTimeSync<AppFhirSyncWorker>(getApplication())
            .shareIn(this, SharingStarted.Eagerly, 10)
            .collect { _pollState.emit(it) }
        }
    
    Diese Coroutine initiiert eine einmalige Synchronisierung mit dem FHIR-Server über den zuvor definierten AppFhirSyncWorker. Anschließend wird die Benutzeroberfläche basierend auf dem Status des Synchronisierungsvorgangs aktualisiert.
  4. Aktualisieren Sie in der Datei PatientListFragment.kt den Text der Funktion handleSyncJobStatus:
    when (syncJobStatus) {
        is SyncJobStatus.Finished -> {
            Toast.makeText(requireContext(), "Sync Finished", Toast.LENGTH_SHORT).show()
            viewModel.searchPatientsByName("")
        }
        else -> {}
    }
    
    Wenn der Synchronisierungsvorgang abgeschlossen ist, wird eine Benachrichtigung für den Nutzer angezeigt und in der App werden alle Patienten angezeigt, indem eine Suche mit einem leeren Namen aufgerufen wird.

Nachdem alles eingerichtet ist, können Sie die App ausführen. Klicken Sie dazu im Menü auf die Schaltfläche Sync. Wenn alles korrekt funktioniert, sollten die Patienten von Ihrem lokalen FHIR-Server heruntergeladen und in der Anwendung angezeigt werden.

Patientenliste

6. Patientendaten ändern und hochladen

In diesem Abschnitt erfahren Sie, wie Sie Patientendaten anhand bestimmter Kriterien ändern und die aktualisierten Daten auf Ihren FHIR-Server hochladen. Konkret tauschen wir die Adressstädte für Patienten mit Wohnsitz in Wakefield und Taunton.

Schritt 1: Änderungslogik in PatientListViewModel einrichten

Der Code in diesem Abschnitt wird der Funktion triggerUpdate in PatientListViewModel hinzugefügt.

  1. Auf die FHIR-Engine zugreifen:Beginnen Sie damit, eine Referenz zur FHIR-Engine in der PatientListViewModel.kt abzurufen.
    viewModelScope.launch {
       val fhirEngine = FhirApplication.fhirEngine(getApplication())
    
    Mit diesem Code wird eine Coroutine im Bereich des ViewModels gestartet und die FHIR-Engine initialisiert.
  2. Nach Patienten aus Wakefield suchen:Verwenden Sie die FHIR-Engine, um nach Patienten mit der Adresse Wakefield zu suchen.
    val patientsFromWakefield =
         fhirEngine.search<Patient> {
           filter(
             Patient.ADDRESS_CITY,
             {
               modifier =  StringFilterModifier.MATCHES_EXACTLY
               value = "Wakefield"
             }
           )
         }
    
    Hier verwenden wir die search-Methode der FHIR-Engine, um Patienten nach ihrer Adresse zu filtern. Das Ergebnis ist eine Liste von Patienten aus Wakefield.
  3. Nach Patienten aus Taunton suchen:Suchen Sie auf ähnliche Weise nach Patienten mit der Stadt Taunton in der Adresse.
    val patientsFromTaunton =
         fhirEngine.search<Patient> {
           filter(
             Patient.ADDRESS_CITY,
             {
               modifier =  StringFilterModifier.MATCHES_EXACTLY
               value = "Taunton"
             }
           )
         }
    
    Wir haben jetzt zwei Patientenlisten – eine aus Wakefield und eine aus Taunton.
  4. Patientenadressen ändern:Gehen Sie jeden Patienten in der Liste patientsFromWakefield durch, ändern Sie die Stadt in Taunton und aktualisieren Sie die Patienten in der FHIR-Engine.
    patientsFromWakefield.forEach {
         it.resource.address.first().city = "Taunton"
         fhirEngine.update(it.resource)
    }
    
    Aktualisieren Sie auf ähnliche Weise jeden Patienten in der Liste patientsFromTaunton, sodass die Stadt in Wakefield geändert wird.
    patientsFromTaunton.forEach {
         it.resource.address.first().city = "Wakefield"
         fhirEngine.update(it.resource)
    }
    
  5. Synchronisierung starten:Nachdem Sie die Daten lokal geändert haben, lösen Sie eine einmalige Synchronisierung aus, damit die Daten auf dem FHIR-Server aktualisiert werden.
    triggerOneTimeSync()
    }
    
    Die schließende geschweifte Klammer } kennzeichnet das Ende der am Anfang gestarteten Coroutine.

Schritt 2: Funktion testen

  1. UI-Tests:Führen Sie Ihre App aus. Klicken Sie im Menü auf die Schaltfläche Update. Die Adressorte für die Patienten Aaron697 und Abby752 sollten vertauscht sein.
  2. Serverbestätigung:Öffnen Sie einen Browser und rufen Sie http://localhost:8080/fhir/Patient/ auf. Prüfen Sie, ob die Stadt der Adresse für die Patienten Aaron697 und Abby752 auf dem lokalen FHIR-Server aktualisiert wurde.

Mit diesen Schritten haben Sie einen Mechanismus implementiert, mit dem Sie Patientendaten ändern und die Änderungen mit Ihrem FHIR-Server synchronisieren können.

7. Nach Patienten anhand des Namens suchen

Die Suche nach Patienten anhand ihrer Namen kann eine benutzerfreundliche Möglichkeit zum Abrufen von Informationen sein. Hier erfahren Sie, wie Sie diese Funktion in Ihre Anwendung einbinden.

Schritt 1: Funktionssignatur aktualisieren

Rufen Sie die Datei PatientListViewModel.kt auf und suchen Sie nach der Funktion mit dem Namen searchPatientsByName. Wir fügen dieser Funktion Code hinzu.

Um die Ergebnisse anhand der angegebenen Namensabfrage zu filtern und die Ergebnisse für die Aktualisierung der Benutzeroberfläche auszugeben, fügen Sie den folgenden bedingten Codeblock ein:

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

Wenn nameQuery nicht leer ist, werden die Suchergebnisse so gefiltert, dass nur Patienten angezeigt werden, deren Namen die angegebene Anfrage enthalten.

Schritt 2: Neue Suchfunktion testen

  1. App neu starten:Nachdem Sie diese Änderungen vorgenommen haben, erstellen Sie Ihre App neu und führen Sie sie aus.
  2. Nach Patienten suchen: Verwenden Sie auf dem Bildschirm mit der Patientenliste die Suchfunktion. Sie sollten nun einen Namen oder einen Teil eines Namens eingeben können, um die Liste der Patienten entsprechend zu filtern.

Nachdem Sie diese Schritte ausgeführt haben, haben Sie Ihre Anwendung verbessert, indem Sie Nutzern die Möglichkeit gegeben haben, effizient nach Patienten anhand ihrer Namen zu suchen. Dies kann die Nutzerfreundlichkeit und die Effizienz beim Abrufen von Daten erheblich verbessern.

8. Glückwunsch!

Sie haben die FHIR Engine-Bibliothek verwendet, um FHIR-Ressourcen in Ihrer App zu verwalten:

  • Sync API zum Synchronisieren von FHIR-Ressourcen mit einem FHIR-Server verwenden
  • Lokale FHIR-Ressourcen mit der Data Access API erstellen, lesen, aktualisieren und löschen
  • Mit der Search API lokale FHIR-Ressourcen durchsuchen

Behandelte Themen

  • Lokalen HAPI FHIR-Server einrichten
  • Testdaten auf den lokalen HAPI FHIR-Server hochladen
  • Android-App mit der FHIR Engine-Bibliothek erstellen
  • Sync API, Data Access API und Search API in der FHIR Engine Library verwenden

Nächste Schritte

  • Dokumentation für die FHIR Engine-Bibliothek ansehen
  • Erweiterte Funktionen der Search API
  • FHIR Engine-Bibliothek in Ihrer eigenen Android-App verwenden

Weitere Informationen