FHIR-Ressourcen mit der FHIR-Engine-Bibliothek verwalten

1. Hinweis

Aufgaben

In diesem Codelab erstellen Sie eine Android-App mit der FHIR Engine Library. Ihre App verwendet die FHIR Engine Library, 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 Library in Ihre Android-Anwendung einbinden
  • Mit der Sync API einen einmaligen oder regelmäßigen Job zum Herunter- und Hochladen von FHIR-Ressourcen einrichten
  • Search API verwenden
  • So erstellen, lesen, aktualisieren und löschen Sie FHIR-Ressourcen lokal mithilfe der Data Access APIs

Voraussetzungen

Wenn Sie noch keine Android-Apps entwickelt haben, können Sie mit dem Erstellen Ihrer ersten App beginnen.

2. Lokalen HAPI FHIR-Server mit Testdaten einrichten

HAPI FHIR ist ein beliebter Open-Source-FHIR-Server. In unserem Codelab verwenden wir einen lokalen HAPI FHIR-Server, mit dem die Android-App eine Verbindung herstellen kann.

Lokalen HAPI FHIR-Server einrichten

  1. Führen Sie den folgenden Befehl in einem Terminal aus, um das neueste Image von HAPI FHIR abzurufen:
    docker pull hapiproject/hapi:latest
    
  2. Erstellen Sie einen HAPI FHIR-Container, indem Sie entweder mit Docker Desktop das zuvor heruntergeladene Image hapiproject/hapi ausführen oder den folgenden Befehl ausführen:
    docker run -p 8080:8080 hapiproject/hapi:latest
    
    Weitere Informationen
  3. Prüfen Sie den Server, indem Sie die URL http://localhost:8080/ in einem Browser öffnen. Die HAPI FHIR-Weboberfläche sollte angezeigt werden.HAPI FHIR-Weboberfläche

Lokalen HAPI FHIR-Server mit Testdaten füllen

Zum Testen unserer Anwendung benötigen wir einige Testdaten auf dem Server. Wir verwenden synthetische Daten, die von Synthea generiert wurden.

  1. Zuerst müssen wir Beispieldaten von synthea-samples herunterladen. Laden Sie synthea_sample_data_fhir_r4_sep2019.zip herunter und entpacken Sie es. Die entpackten Beispieldaten enthalten zahlreiche .json-Dateien, die jeweils ein Transaktionsbundle für einen einzelnen Patienten sind.
  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. Wenn Sie Testdaten für alle Patienten auf den Server hochladen möchten, führen Sie
    for f in *.json; do curl -X POST -H "Content-Type: application/json" -d @$f http://localhost:8080/fhir/ ; done
    
    Das kann jedoch sehr lange dauern und ist für das Codelab nicht erforderlich.
  4. Prüfen Sie, ob die Testdaten auf dem Server verfügbar sind, indem Sie die URL http://localhost:8080/fhir/Patient/ in einem Browser öffnen. Sie sollten den Text HTTP 200 OK und den Abschnitt Response Body der Seite mit Patientendaten in einem FHIR-Bundle als Suchergebnis mit einer Anzahl von total sehen.Testdaten auf dem Server

3. Android-App einrichten

Code herunterladen

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

Das Starterprojekt für dieses Codelab befindet sich unter 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 zuvor heruntergeladenen Quellcode aus.

Android Studio-Startbildschirm

Projekt mit Gradle-Dateien synchronisieren

Die Abhängigkeiten der FHIR Engine Library wurden dem Projekt bereits hinzugefügt. So können Sie die FHIR Engine Library in Ihre App einbinden. Beachten Sie die folgenden Zeilen bis zum 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 den Gradle-Dateien synchronisieren.

Wählen Sie in der Android Studio-Symbolleiste Projekt mit Gradle-Dateien synchronisieren (Schaltfläche „Gradle-Synchronisierung“) aus. Sie können die App auch noch einmal ausführen, um zu prüfen, ob die Abhängigkeiten ordnungsgemäß funktionieren.

Start-App ausführen

Nachdem Sie das Projekt in Android Studio importiert haben, können Sie die App zum ersten Mal ausführen.

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 Library verwenden und eine Instanz der FHIR Engine initiieren. Die folgenden Schritte führen Sie durch den Prozess.

  1. Rufen Sie die Anwendungsklasse auf, in diesem Beispiel FhirApplication.kt in app/src/main/java/com/google/android/fhir/codelabs/engine.
  2. Fügen Sie in der Methode onCreate() den folgenden Code hinzu, um die 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 diese Funktion unterstützt.
    • RECREATE_AT_OPEN: Bestimmt die Datenbankfehlerstrategie. 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 den Localhost reserviert, auf den über den Android-Emulator zugegriffen werden kann. 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) }
    
    So wird sichergestellt, dass die FhirEngine-Instanz erst erstellt wird, wenn zum ersten Mal darauf zugegriffen wird, und nicht sofort beim Starten der App.
  4. Fügen Sie der Klasse FhirApplication die folgende praktische Methode hinzu, um den Zugriff in Ihrer Anwendung zu vereinfachen:
    companion object {
        fun fhirEngine(context: Context) =
            (context.applicationContext as FhirApplication).fhirEngine
    }
    
    Mit dieser statischen Methode können Sie die FHIR Engine-Instanz an einer beliebigen Stelle in der App mithilfe des Kontexts 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. Er verarbeitet Antworten und extrahiert die Ressourcen aus dem zurückgegebenen Bundle, die in der lokalen Datenbank gespeichert werden.
  2. Neue Klasse erstellen AppFhirSyncWorker.kt: Diese Klasse definiert, wie die App mit dem Remote-FHIR-Server über einen Hintergrund-Worker 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 festgelegt, welcher Downloadmanager, Konfliktlöser und welche FHIR-Engine-Instanz für die Synchronisierung verwendet werden soll.
  3. In Ihrem ViewModel PatientListViewModel.kt richten Sie einen Mechanismus für die einmalige Synchronisierung ein. Suchen Sie den folgenden Code und fügen Sie ihn der Funktion triggerOneTimeSync() hinzu:
    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 mithilfe des zuvor definierten AppFhirSyncWorker. Die Benutzeroberfläche wird dann entsprechend dem Status des Synchronisierungsvorgangs aktualisiert.
  4. Aktualisieren Sie in der Datei PatientListFragment.kt den Body 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 dem Nutzer eine Toast-Nachricht angezeigt. Anschließend werden in der App 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 richtig 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. Insbesondere tauschen wir die Städte der Adressen von Patienten in Wakefield und Taunton aus.

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:Rufen Sie zuerst eine Referenz auf die FHIR-Engine in der PatientListViewModel.kt ab.
    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:Mit der FHIR-Engine nach Patienten mit der Adresse Wakefield 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 anhand ihrer Wohnortstadt zu filtern. Das Ergebnis ist eine Liste der Patienten aus Wakefield.
  3. Nach Patienten aus Taunton suchen:Sie können auch nach Patienten mit der Adresse Taunton suchen.
    val patientsFromTaunton =
         fhirEngine.search<Patient> {
           filter(
             Patient.ADDRESS_CITY,
             {
               modifier =  StringFilterModifier.MATCHES_EXACTLY
               value = "Taunton"
             }
           )
         }
    
    Wir haben jetzt zwei Listen mit Patienten, eine aus Wakefield und eine aus Taunton.
  4. Patientenadressen ändern:Gehen Sie alle Patienten in der Liste patientsFromWakefield durch, ändern Sie die Stadt in Taunton und aktualisieren Sie sie in der FHIR-Engine.
    patientsFromWakefield.forEach {
         it.resource.address.first().city = "Taunton"
         fhirEngine.update(it.resource)
    }
    
    Ändern Sie bei allen Patienten in der Liste patientsFromTaunton die Stadt in Wakefield.
    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 Klammer } kennzeichnet das Ende der zu Beginn gestarteten Coroutine.

Schritt 2: Funktion testen

  1. UI-Test:Führen Sie die App aus. Klicken Sie im Menü auf die Schaltfläche Update. Die Städte der Adressen von Patient Aaron697 und Abby752 sollten vertauscht sein.
  2. Serverüberprüfung:Ö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.

Sie haben damit einen Mechanismus zum Ändern von Patientendaten und zum Synchronisieren der Änderungen mit Ihrem FHIR-Server implementiert.

7. Nach Patientennamen suchen

Die Suche nach Patienten anhand ihres Namens kann eine nutzerfreundliche Möglichkeit zum Abrufen von Informationen bieten. In diesem Artikel zeigen wir Ihnen, wie Sie diese Funktion in Ihrer App implementieren.

Schritt 1: Funktionssignatur aktualisieren

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

Wenn Sie die Ergebnisse anhand der angegebenen Namensabfrage filtern und die Ergebnisse für die Aktualisierung der Benutzeroberfläche ausgeben möchten, 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 das Feld nameQuery hier nicht leer ist, werden die Ergebnisse von der Suchfunktion so gefiltert, dass nur Patienten enthalten sind, deren Namen die angegebene Suchanfrage enthalten.

Schritt 2: Neue Suchfunktion testen

  1. App neu starten:Nachdem Sie diese Änderungen vorgenommen haben, erstellen Sie die App neu und führen Sie sie aus.
  2. Nach Patienten suchen: Verwenden Sie auf dem Bildschirm mit der Patientenliste die Suchfunktion. Sie sollten jetzt 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, können Nutzer jetzt effizient nach Patientennamen suchen. Dies kann die Nutzerfreundlichkeit und Effizienz der Datenabfrage erheblich verbessern.

8. Glückwunsch!

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

  • FHIR-Ressourcen mit einem FHIR-Server über die Sync API synchronisieren
  • Mit der Data Access API lokale FHIR-Ressourcen erstellen, lesen, aktualisieren und löschen
  • Mit der Search API nach lokalen FHIR-Ressourcen suchen

Behandelte Themen

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

Nächste Schritte

  • Dokumentation für die FHIR Engine Library
  • Erweiterte Funktionen der Search API
  • FHIR Engine Library in Ihrer eigenen Android-App anwenden

Weitere Informationen