1. Zanim zaczniesz
Co utworzysz
W tym ćwiczeniu z programowania utworzysz aplikację na Androida za pomocą biblioteki FHIR Engine. Aplikacja będzie używać biblioteki FHIR Engine do pobierania zasobów FHIR z serwera FHIR i przesyłania na serwer wszelkich zmian wprowadzonych lokalnie.
Czego się nauczysz
- Jak utworzyć lokalny serwer HAPI FHIR za pomocą Dockera
- Jak zintegrować bibliotekę FHIR Engine z aplikacją na Androida
- Jak użyć interfejsu Sync API, aby skonfigurować jednorazowe lub okresowe zadanie pobierania i przesyłania zasobów FHIR
- Jak korzystać z interfejsu Search API
- Jak używać interfejsów API dostępu do danych do tworzenia, odczytywania, aktualizowania i usuwania zasobów FHIR lokalnie
Czego potrzebujesz
- Docker (pobierz Dockera)
- Nowa wersja Android Studio (4.1.2 lub nowsza)
- Emulator Androida lub fizyczne urządzenie z Androidem 7.0 Nougat lub nowszym.
- Przykładowy kod
- podstawowa znajomość tworzenia aplikacji na Androida w Kotlinie;
Jeśli nie tworzysz jeszcze aplikacji na Androida, możesz zacząć od utworzenia pierwszej aplikacji.
2. Konfigurowanie lokalnego serwera HAPI FHIR za pomocą danych testowych
HAPI FHIR to popularny serwer FHIR typu open source. W naszym laboratorium kodu używamy lokalnego serwera HAPI FHIR, z którym łączy się aplikacja na Androida.
Konfigurowanie lokalnego serwera HAPI FHIR
- Aby uzyskać najnowszy obraz HAPI FHIR, uruchom to polecenie w terminalu:
docker pull hapiproject/hapi:latest
- Utwórz kontener HAPI FHIR, używając Docker Desktop do uruchomienia wcześniej pobranego obrazu
hapiproject/hapi
lub wykonując to polecenie: Więcej informacjidocker run -p 8080:8080 hapiproject/hapi:latest
- Sprawdź serwer, otwierając adres URL
http://localhost:8080/
w przeglądarce. Powinien wyświetlić się interfejs internetowy HAPI FHIR.
Wypełnianie lokalnego serwera HAPI FHIR danymi testowymi
Aby przetestować naszą aplikację, potrzebujemy na serwerze niektórych danych testowych. Użyjemy danych syntetycznych wygenerowanych przez Synthea.
- Najpierw musimy pobrać przykładowe dane z synthea-samples. Pobierz i wyodrębnij plik
synthea_sample_data_fhir_r4_sep2019.zip
. Rozpakowane przykładowe dane zawierają wiele plików.json
, z których każdy stanowi pakiet transakcji dotyczącej konkretnego pacjenta. - Prześlemy dane testowe dotyczące 3 pacjentów na lokalny serwer HAPI FHIR. Uruchom to polecenie w katalogu zawierającym pliki 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/
- Aby przesłać na serwer testowe dane wszystkich pacjentów, uruchom
To może jednak zająć dużo czasu i nie jest konieczne do wykonania ćwiczenia.for f in *.json; do curl -X POST -H "Content-Type: application/json" -d @$f http://localhost:8080/fhir/ ; done
- Aby sprawdzić, czy dane testowe są dostępne na serwerze, otwórz adres URL
http://localhost:8080/fhir/Patient/
w przeglądarce. W wynikach wyszukiwania powinna się wyświetlić strona zawierająca dane pacjenta w pakiecie FHIR z tekstemHTTP 200 OK
i sekcjąResponse Body
oraz liczbatotal
.
3. Konfigurowanie aplikacji na Androida
Pobieranie kodu
Aby pobrać kod do tego ćwiczenia, sklonuj repozytorium Android FHIR SDK: git clone https://github.com/google/android-fhir.git
Projekt startowy tego Codelab znajduje się w folderze codelabs/engine
.
Zaimportuj aplikację do Android Studio
Zacznij od zaimportowania aplikacji startowej do Android Studio.
Otwórz Android Studio, wybierz Importuj projekt (Gradle, Eclipse ADT itp.) i wybierz folder codelabs/engine/
z poprzednio pobranego kodu źródłowego.
Synchronizacja projektu z plikami Gradle
Dla Twojej wygody zależności biblioteki FHIR Engine zostały już dodane do projektu. Umożliwi Ci to zintegrowanie biblioteki FHIR Engine w swojej aplikacji. Sprawdź te wiersze na końcu pliku app/build.gradle.kts
projektu:
dependencies {
// ...
implementation("com.google.android.fhir:engine:1.1.0")
}
Aby mieć pewność, że wszystkie zależności są dostępne dla aplikacji, na tym etapie zsynchronizuj projekt z plikami Gradle.
Na pasku narzędzi Android Studio kliknij Synchronizuj projekt z plikami Gradle (). Możesz też ponownie uruchomić aplikację, aby sprawdzić, czy zależności działają prawidłowo.
Uruchamianie aplikacji startowej
Po zaimportowaniu projektu do Android Studio możesz uruchomić aplikację po raz pierwszy.
Uruchom emulator Android Studio i kliknij Uruchom () na pasku narzędzi Android Studio.
4. Tworzenie instancji FHIR Engine
Aby włączyć silnik FHIR w aplikacji na Androida, musisz użyć biblioteki FHIR Engine i uruchomić instancję FHIR Engine. Poniżej znajdziesz instrukcje, które pomogą Ci przejść przez cały proces.
- Przejdź do klasy Application, która w tym przykładzie to
FhirApplication.kt
i znajduje się wapp/src/main/java/com/google/android/fhir/codelabs/engine
. - Aby zainicjować silnik FHIR, dodaj do metody
onCreate()
ten kod: Uwagi: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
: włącza szyfrowanie danych, jeśli urządzenie obsługuje tę funkcję.RECREATE_AT_OPEN
: określa strategię dotyczącą błędów bazy danych. W takim przypadku, jeśli podczas otwierania wystąpi błąd, baza danych zostanie utworzona ponownie.baseUrl
wServerConfiguration
: to jest podstawowy adres URL serwera FHIR. Podany adres IP10.0.2.2
jest zarezerwowany specjalnie dla localhosta i jest dostępny z emulatora Androida. Więcej informacji
- W klasie
FhirApplication
dodaj ten wiersz, aby leniwie utworzyć instancję silnika FHIR: W ten sposób instancja FhirEngine jest tworzona tylko wtedy, gdy jest po raz pierwszy używana, a nie natychmiast po uruchomieniu aplikacji.private val fhirEngine: FhirEngine by lazy { FhirEngineProvider.getInstance(this) }
- Aby ułatwić dostęp do klasy
FhirApplication
w całej aplikacji, dodaj do niej tę wygodną metodę: Ta metoda statyczna umożliwia odzyskiwanie instancji FHIR Engine z dowolnego miejsca w aplikacji za pomocą kontekstu.companion object { fun fhirEngine(context: Context) = (context.applicationContext as FhirApplication).fhirEngine }
5. Synchronizacja danych z serwerem FHIR
- Utwórz nowe zajęcia
DownloadWorkManagerImpl.kt
. W tej lekcji określisz, jak aplikacja pobiera kolejny zasób z listy do pobrania: Ta klasa ma kolejkę typów zasobów, które chce pobrać. Przetwarza ona odpowiedzi i wyodrębnia z zwróconego pakietu zasoby, które są zapisywane w lokalnej bazie danych.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 } }
- Utwórz nową klasę
AppFhirSyncWorker.kt
. Ta klasa określa, jak aplikacja będzie synchronizować się z zdalnym serwerem FHIR za pomocą podprocesu w tle. Tutaj definiujemy, którego menedżera pobierania, rozwiązywania konfliktów i instancji silnika FHIR używać do synchronizacji.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, ) }
- W ViewModel
PatientListViewModel.kt
skonfigurujesz mechanizm jednorazowej synchronizacji. Zlokalizuj i dodaj do funkcjitriggerOneTimeSync()
ten kod: Ta coroutine inicjuje jednorazową synchronizację z serwerem FHIR za pomocą wcześniej zdefiniowanego obiektu AppFhirSyncWorker. Następnie zaktualizuje interfejs na podstawie stanu procesu synchronizacji.viewModelScope.launch { Sync.oneTimeSync<AppFhirSyncWorker>(getApplication()) .shareIn(this, SharingStarted.Eagerly, 10) .collect { _pollState.emit(it) } }
- W pliku
PatientListFragment.kt
zaktualizuj ciało funkcjihandleSyncJobStatus
: Po zakończeniu procesu synchronizacji wyświetli się komunikat informujący o tym użytkownika, a następnie aplikacja wyświetli wszystkich pacjentów, wywołując wyszukiwanie z pustą nazwą.when (syncJobStatus) { is SyncJobStatus.Finished -> { Toast.makeText(requireContext(), "Sync Finished", Toast.LENGTH_SHORT).show() viewModel.searchPatientsByName("") } else -> {} }
Gdy wszystko będzie gotowe, uruchom aplikację. W menu kliknij przycisk Sync
. Jeśli wszystko działa prawidłowo, pacjenci z lokalnego serwera FHIR powinni zostać pobrani i wyświetleni w aplikacji.
6. Modyfikowanie i przesyłanie danych pacjentów
W tej sekcji poprowadzimy Cię przez proces modyfikowania danych pacjenta na podstawie określonych kryteriów i przesyłania zaktualizowanych danych na serwer FHIR. W szczególności zamienimy miasta adresów pacjentów mieszkających w Wakefield
i Taunton
.
Krok 1. Skonfiguruj logikę modyfikacji w PatientListViewModel.
Kod z tej sekcji jest dodawany do funkcji triggerUpdate
w pliku PatientListViewModel
.
- Uzyskiwanie dostępu do silnika FHIR: zacznij od uzyskania odwołania do silnika FHIR w
PatientListViewModel.kt
. Ten kod uruchamia coroutine w zakresie ViewModel i inicjalizuje silnik FHIR.viewModelScope.launch { val fhirEngine = FhirApplication.fhirEngine(getApplication())
- Wyszukaj pacjentów z Wakefield: użyj mechanizmu FHIR do wyszukania pacjentów z adresem w mieście
Wakefield
. Tutaj używamy metodyval patientsFromWakefield = fhirEngine.search<Patient> { filter( Patient.ADDRESS_CITY, { modifier = StringFilterModifier.MATCHES_EXACTLY value = "Wakefield" } ) }
search
silnika FHIR do filtrowania pacjentów według miasta ich adresu. Wynikiem będzie lista pacjentów z Wakefield. - Wyszukiwanie pacjentów z Taunton: podobnie możesz wyszukać pacjentów, których adres znajduje się w mieście
Taunton
. Mamy teraz 2 listy pacjentów – jedną z Wakefield, a drugą z Taunton.val patientsFromTaunton = fhirEngine.search<Patient> { filter( Patient.ADDRESS_CITY, { modifier = StringFilterModifier.MATCHES_EXACTLY value = "Taunton" } ) }
- Modyfikowanie adresów pacjentów: przejrzyj listę
patientsFromWakefield
, zmień miasto naTaunton
i zaktualizuj dane w mechanizmie FHIR. Analogicznie zaktualizuj każdego pacjenta na liściepatientsFromWakefield.forEach { it.resource.address.first().city = "Taunton" fhirEngine.update(it.resource) }
patientsFromTaunton
, aby zmienić jego miasto naWakefield
.patientsFromTaunton.forEach { it.resource.address.first().city = "Wakefield" fhirEngine.update(it.resource) }
- Rozpoczęcie synchronizacji: po zmodyfikowaniu danych lokalnie należy wywołać jednorazową synchronizację, aby dane zostały zaktualizowane na serwerze FHIR.
Zamykająca klamratriggerOneTimeSync() }
}
oznacza koniec uruchamianej na początku łańcucha coroutine.
Krok 2. Przetestuj funkcję
- Testowanie interfejsu użytkownika: uruchom aplikację. W menu kliknij przycisk
Update
. Powinny się zmienić miasta adresów pacjentówAaron697
iAbby752
. - Weryfikacja serwera: otwórz przeglądarkę i przejdź na stronę
http://localhost:8080/fhir/Patient/
. Sprawdź, czy adres miasta dla pacjentówAaron697
iAbby752
jest zaktualizowany na lokalnym serwerze FHIR.
Po wykonaniu tych czynności udało Ci się wdrożyć mechanizm modyfikowania danych pacjenta i synchronizowania zmian z serwerem FHIR.
7. Wyszukaj pacjentów według nazwiska
Wyszukiwanie pacjentów według nazwiska może być wygodnym sposobem na uzyskiwanie informacji. Poniżej poprowadzimy Cię przez proces implementacji tej funkcji w aplikacji.
Krok 1. Zaktualizuj sygnaturę funkcji
Otwórz plik PatientListViewModel.kt
i znajdź funkcję o nazwie searchPatientsByName
. Dodamy do niej kod.
Aby filtrować wyniki na podstawie podanego zapytania o nazwę i wysyłać je do interfejsu w celu ich zaktualizowania, dodaj ten blok kodu warunkowego:
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 }
}
}
Jeśli nameQuery
nie jest pusty, funkcja wyszukiwania odfiltruje wyniki, aby uwzględnić tylko pacjentów, których nazwiska zawierają określone zapytanie.
Krok 2. Przetestuj nową funkcję wyszukiwania
- Uruchom ponownie aplikację: po wprowadzeniu tych zmian ponownie skompiluj i uruchom aplikację.
- Wyszukiwanie pacjentów: na ekranie listy pacjentów użyj funkcji wyszukiwania. Teraz możesz wpisać nazwę (lub jej część), aby odfiltrować listę pacjentów.
Po wykonaniu tych czynności aplikacja będzie umożliwiać użytkownikom wyszukiwanie pacjentów po nazwisku. Może to znacznie ulepszyć wrażenia użytkowników i skuteczność pobierania danych.
8. Gratulacje!
Użyjesz biblioteki FHIR Engine do zarządzania zasobami FHIR w aplikacji:
- Synchronizowanie zasobów FHIR z serwerem FHIR za pomocą interfejsu Sync API
- Tworzenie, odczytywanie, aktualizowanie i usuwanie lokalnych zasobów FHIR za pomocą interfejsu Data Access API
- Używanie interfejsu Search API do wyszukiwania lokalnych zasobów FHIR
Omówione zagadnienia
- Jak skonfigurować lokalny serwer HAPI FHIR
- Jak przesłać dane testowe na lokalny serwer FHIR HAPI
- Jak utworzyć aplikację na Androida za pomocą biblioteki FHIR Engine
- Jak używać interfejsów API synchronizacji, dostępu do danych i wyszukiwania w bibliotece silnika FHIR
Następne kroki
- Zapoznaj się z dokumentacją biblioteki FHIR Engine
- Poznaj zaawansowane funkcje interfejsu Search API
- Stosowanie biblioteki FHIR Engine w aplikacji na Androida