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 Anwendung 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
  • So integrieren Sie die FHIR-Engine-Bibliothek in Ihre Android-Anwendung
  • Mit der Sync API einen einmaligen oder regelmäßigen Job zum Herunterladen und Hochladen von FHIR-Ressourcen einrichten
  • So verwenden Sie die Search API
  • Wie Sie die Data Access APIs verwenden, um FHIR-Ressourcen lokal zu erstellen, zu lesen, zu aktualisieren und zu löschen

Voraussetzungen

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

2. Lokalen HAPI-FHIR-Server mit Testdaten einrichten

HAPI FHIR ist ein beliebter Open-Source-FHIR-Server. Wir verwenden in unserem Codelab einen lokalen HAPI-FHIR-Server, zu 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. Verwenden Sie dazu entweder Docker Desktop, um das zuvor heruntergeladene Image hapiproject/hapi auszuführen, oder führen Sie den folgenden Befehl aus:
    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. Sie sollten die HAPI FHIR-Weboberfläche sehen.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-sample herunterladen. Laden Sie synthea_sample_data_fhir_r4_sep2019.zip herunter und extrahieren Sie es. Die entpackten Beispieldaten enthalten zahlreiche .json-Dateien, von denen jede ein Transaktions-Bundle für einen einzelnen Patienten ist.
  2. Wir laden Testdaten für drei Patienten auf den lokalen HAPI FHIR-Server hoch. Führen Sie den folgenden Befehl in dem Verzeichnis aus, das die JSON-Dateien enthält:
    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. Führen Sie
    for f in *.json; do curl -X POST -H "Content-Type: application/json" -d @$f http://localhost:8080/fhir/ ; done
    
    aus, um Testdaten für alle Patienten auf den Server hochzuladen. Das 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, indem Sie die URL http://localhost:8080/fhir/Patient/ in einem Browser öffnen. Der Text HTTP 200 OK und der Abschnitt Response Body der Seite mit Patientendaten in einem FHIR-Bundle sollten als Suchergebnis mit einer Anzahl von total angezeigt werden.Daten auf dem Server testen

3. Android-App einrichten

Code herunterladen

Klonen Sie das Android FHIR SDK-Repository, um den Code für dieses Codelab herunterzuladen: git clone https://github.com/google/android-fhir.git

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

App in Android Studio importieren

Zunächst importieren wir die Starter-App in Android Studio.

Öffnen Sie Android Studio, wählen Sie Projekt importieren (Gradle, Eclipse ADT usw.) und dann 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. Auf diese Weise können Sie die FHIR-Engine-Bibliothek in Ihre Anwendung integrieren. Sehen Sie sich die folgenden Zeilen am Ende der Datei app/build.gradle.kts Ihres Projekts an:

dependencies {
    // ...

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

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 für die Gradle-Synchronisierung) aus. Außerdem führen Sie die Anwendung noch einmal aus, um zu prüfen, ob die Abhängigkeiten korrekt 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 Run (Schaltfläche „Ausführen“).

Hello World App

4. FHIR-Engine-Instanz erstellen

Um die FHIR-Engine in Ihre Android-App einzubinden, müssen Sie die FHIR-Engine-Bibliothek verwenden und eine Instanz der FHIR-Engine initiieren. Die unten beschriebenen Schritte führen Sie durch den Prozess.

  1. Rufen Sie Ihre Anwendungsklasse auf, in diesem Beispiel FhirApplication.kt. Sie befindet sich 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 dies 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 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 nur erstellt wird, wenn zum ersten Mal darauf zugegriffen wird, und nicht sofort beim Start der Anwendung.
  4. Fügen Sie der FhirApplication-Klasse die folgende praktische Methode hinzu, um in der gesamten Anwendung leichter darauf zugreifen zu können:
    companion object {
        fun fhirEngine(context: Context) =
            (context.applicationContext as FhirApplication).fhirEngine
    }
    
    Mit dieser statischen Methode können Sie die FHIR Engine-Instanz mithilfe des Kontexts von jeder beliebigen Stelle in der Anwendung abrufen.

5. Daten mit FHIR-Server synchronisieren

  1. Erstelle einen neuen DownloadWorkManagerImpl.kt-Kurs. 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 soll. Er verarbeitet Antworten und extrahiert die Ressourcen aus dem zurückgegebenen Bundle, das in der lokalen Datenbank gespeichert wird.
  2. Neue Klasse erstellen 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)
    }
    
    Hier haben wir definiert, welcher Download-Manager, welcher Konfliktlöser und welche FHIR-Engine-Instanz für die Synchronisierung verwendet werden sollen.
  3. In ViewModel (PatientListViewModel.kt) richten Sie einen Mechanismus zur einmaligen Synchronisierung ein. Suchen Sie den folgenden Code und fügen Sie ihn der triggerOneTimeSync()-Funktion hinzu:
    viewModelScope.launch {
          Sync.oneTimeSync<AppFhirSyncWorker>(getApplication())
            .shareIn(this, SharingStarted.Eagerly, 10)
            .collect { _pollState.emit(it) }
        }
    
    Diese Koroutine initiiert eine einmalige Synchronisierung mit dem FHIR-Server mithilfe des zuvor definierten AppFhirSyncWorker. Anschließend wird die Benutzeroberfläche entsprechend dem Status des Synchronisierungsvorgangs aktualisiert.
  4. Aktualisieren Sie in der Datei PatientListFragment.kt den Hauptteil der Funktion handleSyncJobStatus:
    when (syncJobStatus) {
        is SyncJobStatus.Finished -> {
            Toast.makeText(requireContext(), "Sync Finished", Toast.LENGTH_SHORT).show()
            viewModel.searchPatientsByName("")
        }
        else -> {}
    }
    
    Wenn die Synchronisierung abgeschlossen ist, wird der Nutzer in einer Toast-Nachricht darüber informiert. Die App zeigt dann alle Patienten an, indem sie eine Suche mit einem leeren Namen aufruft.

Nachdem nun alles eingerichtet ist, führen Sie Ihre App aus. Klicken Sie im Menü auf die Schaltfläche Sync. Wenn alles ordnungsgemäß funktioniert, sollten Sie sehen, dass 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 werden wir die Städte der Adresse für Patienten mit Wohnsitz in Wakefield und Taunton austauschen.

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 einen Verweis auf die FHIR-Engine in der PatientListViewModel.kt ab.
    viewModelScope.launch {
       val fhirEngine = FhirApplication.fhirEngine(getApplication())
    
    Dieser Code startet eine Koroutine im Bereich von ViewModel und initialisiert die FHIR-Engine.
  2. Nach Patienten aus Wakefield suchen: Verwenden Sie die FHIR-Engine, um nach Patienten mit der Adressstadt 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 ihrem Adressort zu filtern. Das Ergebnis ist eine Liste von Patienten aus Wakefield.
  3. Nach Patienten in Taunton suchen:Suchen Sie auf ähnliche Weise nach Patienten mit der Adresse Taunton.
    val patientsFromTaunton =
         fhirEngine.search<Patient> {
           filter(
             Patient.ADDRESS_CITY,
             {
               modifier =  StringFilterModifier.MATCHES_EXACTLY
               value = "Taunton"
             }
           )
         }
    
    Wir haben jetzt zwei Listen mit Patienten: eine von Wakefield und eine von Taunton.
  4. Patientenadressen ändern: Gehen Sie jeden Patienten in der patientsFromWakefield-Liste durch, ändern Sie seinen Ort in Taunton und aktualisieren Sie ihn in der FHIR-Engine.
    patientsFromWakefield.forEach {
         it.resource.address.first().city = "Taunton"
         fhirEngine.update(it.resource)
    }
    
    Aktualisieren Sie analog dazu jeden Patienten in der patientsFromTaunton-Liste, um den Ort in Wakefield zu ändern.
    patientsFromTaunton.forEach {
         it.resource.address.first().city = "Wakefield"
         fhirEngine.update(it.resource)
    }
    
  5. Synchronisierung initiieren: Nachdem Sie die Daten lokal geändert haben, lösen Sie eine einmalige Synchronisierung aus, um sicherzustellen, dass die Daten auf dem FHIR-Server aktualisiert werden.
    triggerOneTimeSync()
    }
    
    Die schließende Klammer } gibt das Ende der Koroutine an, die am Anfang gestartet wurde.

Schritt 2: Funktion testen

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

Mit diesen Schritten haben Sie erfolgreich einen Mechanismus implementiert, um Patientendaten zu ändern und die Änderungen mit Ihrem FHIR-Server zu synchronisieren.

7. Patienten anhand des Namens suchen

Die Suche nach Patienten anhand des Namens kann eine nutzerfreundliche Methode sein, Informationen abzurufen. Hier führen wir Sie durch den Prozess zur Implementierung dieser Funktion in Ihrer Anwendung.

Schritt 1: Funktionssignatur aktualisieren

Gehen Sie zur Datei PatientListViewModel.kt und suchen Sie die Funktion searchPatientsByName. Wir fügen dieser Funktion Code hinzu.

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

    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 hier nameQuery nicht leer ist, filtert die Suchfunktion die Ergebnisse so, dass nur Patienten aufgeführt werden, deren Namen die angegebene Suchanfrage enthalten.

Schritt 2: Neue Suchfunktionen 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 die Suchfunktion auf dem Bildschirm mit der Patientenliste. Sie sollten jetzt einen Namen (oder einen Teil eines Namens) eingeben können, um die Liste der behandelten Personen entsprechend zu filtern.

Nachdem Sie diese Schritte ausgeführt haben, haben Sie Ihre Anwendung optimiert, indem Sie Nutzern die Möglichkeit geben, Patienten effizient anhand ihres Namens zu suchen. Dies kann die Nutzererfahrung und die Effizienz beim Datenabruf erheblich verbessern.

8. Glückwunsch!

Sie haben die FHIR-Engine-Bibliothek zum Verwalten von FHIR-Ressourcen in Ihrer Anwendung verwendet:

  • Sync API verwenden, um FHIR-Ressourcen mit einem FHIR-Server zu synchronisieren
  • Mit der Data Access API lokale FHIR-Ressourcen erstellen, lesen, aktualisieren und löschen
  • Search API verwenden, um lokale FHIR-Ressourcen zu suchen

Behandelte Themen

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

Nächste Schritte

  • Dokumentation zur FHIR-Engine-Bibliothek ansehen
  • Erweiterte Funktionen der Search API
  • Wenden Sie die FHIR-Engine-Bibliothek in Ihrer eigenen Android-App an

Weitere Informationen