1. לפני שמתחילים
מה תפַתחו
בסדנת הקוד הזו תלמדו ליצור אפליקציית Android באמצעות ספריית FHIR Engine. האפליקציה תשתמש בספריית FHIR Engine כדי להוריד משאבים של FHIR משרת FHIR, ולהעלות שינויים מקומיים לשרת.
מה תלמדו
- איך יוצרים שרת HAPI FHIR מקומי באמצעות Docker
- איך משלבים את ספריית FHIR Engine באפליקציה ל-Android
- איך משתמשים ב-Sync API כדי להגדיר משימה חד-פעמית או תקופתית להורדה ולהעלאה של משאבי FHIR
- איך משתמשים ב-Search API
- איך משתמשים ב-Data Access APIs כדי ליצור, לקרוא, לעדכן ולמחוק משאבי FHIR באופן מקומי
מה נדרש
- Docker (הורדת Docker)
- גרסה עדכנית של Android Studio (מגרסה 4.1.2 ואילך)
- Android Emulator או מכשיר Android פיזי עם Android 7.0 Nougat ואילך
- הקוד לדוגמה
- ידע בסיסי בפיתוח Android ב-Kotlin
אם עדיין לא יצרתם אפליקציות ל-Android, תוכלו להתחיל בפיתוח האפליקציה הראשונה.
2. הגדרת שרת HAPI FHIR מקומי עם נתוני בדיקה
HAPI FHIR הוא שרת FHIR פופולרי בקוד פתוח. אנחנו משתמשים בשרת HAPI FHIR מקומי ב-codelab שלנו, שאליו מתחברת אפליקציית Android.
הגדרת השרת המקומי של HAPI FHIR
- מריצים את הפקודה הבאה בטרמינל כדי לקבל את קובץ האימג' העדכני ביותר של HAPI FHIR
docker pull hapiproject/hapi:latest
- יוצרים קונטיינר של HAPI FHIR באמצעות Docker Desktop כדי להריץ את קובץ האימג'
hapiproject/hapi
שהורדתם קודם, או באמצעות הפקודה הבאה: מידע נוסףdocker run -p 8080:8080 hapiproject/hapi:latest
- בודקים את השרת על ידי פתיחת כתובת ה-URL
http://localhost:8080/
בדפדפן. הממשק האינטרנטי של HAPI FHIR אמור להופיע.
איך מאכלסים את שרת HAPI FHIR המקומי בנתוני בדיקה
כדי לבדוק את האפליקציה שלנו, נצטרך נתוני בדיקה מסוימים בשרת. נשתמש בנתונים סינתטיים שנוצרו על ידי Synthea.
- קודם כול, צריך להוריד נתונים לדוגמה מ-synthea-samples. מורידים את
synthea_sample_data_fhir_r4_sep2019.zip
ומחליצים אותו. בנתוני הדוגמה ללא הקיפול יש מספר רב של קבצים מסוג.json
, כל אחד מהם הוא חבילה של עסקאות של חולה ספציפי. - נעלול נתוני בדיקה של שלושה חולים לשרת המקומי של 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/
- כדי להעלות נתוני בדיקה של כל המטופלים לשרת, מריצים את הפקודה
עם זאת, השלמת התהליך עשויה להימשך זמן רב והיא לא הכרחית לקודלאב.for f in *.json; do curl -X POST -H "Content-Type: application/json" -d @$f http://localhost:8080/fhir/ ; done
- פותחים את כתובת ה-URL
http://localhost:8080/fhir/Patient/
בדפדפן כדי לוודא שנתוני הבדיקה זמינים בשרת. הטקסטHTTP 200 OK
והקטעResponse Body
בדף שמכיל את נתוני המטופלים ב-FHIR Bundle אמורים להופיע כתוצאת החיפוש עם ספירה שלtotal
.
3. הגדרת האפליקציה ל-Android
הורדת הקוד
כדי להוריד את הקוד של סדנת הקוד הזו, צריך לשכפל את המאגר של Android FHIR SDK: git clone https://github.com/google/android-fhir.git
הפרויקט למתחילים ב-Codelab הזה נמצא ב-codelabs/engine
.
ייבוא האפליקציה ל-Android Studio
מתחילים בייבוא האפליקציה למתחילים ל-Android Studio.
פותחים את Android Studio, בוחרים באפשרות Import Project (Gradle, Eclipse ADT, etc.) ובוחרים את התיקייה codelabs/engine/
מקוד המקור שהורדתם מקודם.
סנכרון הפרויקט עם קובצי Gradle
לנוחותכם, יחסי התלות של ספריית FHIR Engine כבר נוספו לפרויקט. כך תוכלו לשלב את ספריית FHIR Engine באפליקציה. מוסיפים את השורות הבאות עד לסוף הקובץ app/build.gradle.kts
של הפרויקט:
dependencies {
// ...
implementation("com.google.android.fhir:engine:1.1.0")
}
כדי לוודא שכל יחסי התלות זמינים לאפליקציה, צריך לסנכרן את הפרויקט עם קובצי Gradle בשלב הזה.
בוחרים באפשרות סנכרון הפרויקט עם קובצי Gradle () בסרגל הכלים של Android Studio. אפשר גם להריץ את האפליקציה שוב כדי לבדוק אם יחסי התלות פועלים כמו שצריך.
הפעלת האפליקציה למתחילים
עכשיו, אחרי שמייבאים את הפרויקט ל-Android Studio, אפשר להריץ את האפליקציה בפעם הראשונה.
מפעילים את המהדר של Android Studio ולוחצים על סמל ההפעלה () בסרגל הכלים של Android Studio.
4. יצירת מכונה של FHIR Engine
כדי לשלב את FHIR Engine באפליקציה ל-Android, צריך להשתמש בספריית FHIR Engine ולהפעיל מכונה של FHIR Engine. השלבים הבאים ילוו אתכם בתהליך.
- עוברים למחלקת האפליקציה, שבדוגמאות האלה היא
FhirApplication.kt
, שנמצאת ב-app/src/main/java/com/google/android/fhir/codelabs/engine
. - בתוך השיטה
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
, שמורה במיוחד ל-localhost, וניתן לגשת אליה מהמכונה הווירטואלית של Android. מידע נוסף
- בכיתה
FhirApplication
, מוסיפים את השורה הבאה כדי ליצור מופע של FHIR Engine באופן עצל: כך מוודאים שהמכונה של FhirEngine נוצרת רק כשנכנסים אליה בפעם הראשונה, ולא מיד כשהאפליקציה מתחילה לפעול.private val fhirEngine: FhirEngine by lazy { FhirEngineProvider.getInstance(this) }
- מוסיפים את שיטת הנוחות הבאה לכיתה
FhirApplication
כדי לאפשר גישה נוחה יותר לכל מקום באפליקציה: השיטה הסטטית הזו מאפשרת לאחזר את המכונה של FHIR Engine מכל מקום באפליקציה באמצעות ההקשר.companion object { fun fhirEngine(context: Context) = (context.applicationContext as FhirApplication).fhirEngine }
5. סנכרון נתונים עם שרת FHIR
- יוצרים כיתה חדשה
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 } }
- יוצרים כיתה חדשה
AppFhirSyncWorker.kt
הכיתה הזו מגדירה איך האפליקציה תבצע סנכרון עם שרת FHIR המרוחק באמצעות תהליך עבודה ברקע. כאן הגדירו את מנהל ההורדות, את פותר ההתנגשויות ואת המכונה של מנוע FHIR שבהם נעשה שימוש בסנכרון.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, ) }
- ב-ViewModel,
PatientListViewModel.kt
, תגדירו מנגנון סנכרון חד-פעמי. מאתרים את הקוד הזה ומוסיפים אותו לפונקציהtriggerOneTimeSync()
: פונקציית ה-coroutine הזו מפעילה סנכרון חד-פעמי עם שרת FHIR באמצעות AppFhirSyncWorker שהגדרנו קודם. לאחר מכן, ממשק המשתמש יתעדכן בהתאם למצב של תהליך הסנכרון.viewModelScope.launch { Sync.oneTimeSync<AppFhirSyncWorker>(getApplication()) .shareIn(this, SharingStarted.Eagerly, 10) .collect { _pollState.emit(it) } }
- בקובץ
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
- גישה למנוע FHIR:מתחילים בקבלת הפניה למנוע FHIR ב-
PatientListViewModel.kt
. הקוד הזה מפעיל קורוטין בהיקף של ViewModel ומפעיל את מנוע FHIR.viewModelScope.launch { val fhirEngine = FhirApplication.fhirEngine(getApplication())
- חיפוש של חולים מווייקפילד:משתמשים במנוע FHIR כדי לחפש חולים שהעיר בכתובת שלהם היא
Wakefield
. כאן אנחנו משתמשים בשיטהval patientsFromWakefield = fhirEngine.search<Patient> { filter( Patient.ADDRESS_CITY, { modifier = StringFilterModifier.MATCHES_EXACTLY value = "Wakefield" } ) }
search
של מנוע FHIR כדי לסנן חולים על סמך העיר של הכתובת שלהם. התוצאה תהיה רשימה של חולים מווייקפילד. - חיפוש מטופלים מתל אביב:באופן דומה, אפשר לחפש מטופלים שהעיר בכתובת שלהם היא
Taunton
. עכשיו יש לנו שתי רשימות של חולים – אחת מווייקפילד והשנייה מטאונטון.val patientsFromTaunton = fhirEngine.search<Patient> { filter( Patient.ADDRESS_CITY, { modifier = StringFilterModifier.MATCHES_EXACTLY value = "Taunton" } ) }
- שינוי כתובות של חולים:עוברים על כל החולים ברשימה
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) }
- התחלת סנכרון:אחרי שמבצעים שינוי בנתונים באופן מקומי, מפעילים סנכרון חד-פעמי כדי לוודא שהנתונים מתעדכנים בשרת FHIR.
סוגריים מסולסלים סוגרייםtriggerOneTimeSync() }
}
מסמנים את הסוף של פונקציית ה-coroutine שהופעל בהתחלה.
שלב 2: בדיקת הפונקציונליות
- בדיקת ממשק המשתמש:מריצים את האפליקציה. לוחצים על הלחצן
Update
בתפריט. ערים הכתובות של החוליםAaron697
ו-Abby752
אמורות להשתנות. - אימות שרת:פותחים דפדפן ועוברים לכתובת
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: בדיקת הפונקציונליות החדשה של החיפוש
- הפעלה מחדש של האפליקציה:אחרי ביצוע השינויים האלה, צריך ליצור מחדש את האפליקציה ולהפעיל אותה.
- חיפוש של מטופלים: במסך רשימת המטופלים, משתמשים בפונקציית החיפוש. עכשיו אמורה להיות לך אפשרות להזין שם (או חלק משם) כדי לסנן את רשימת החולים בהתאם.
אחרי ביצוע השלבים האלה, האפליקציה תהיה משופרת יותר כי המשתמשים יוכלו לחפש חולים בצורה יעילה לפי השמות שלהם. כך אפשר לשפר באופן משמעותי את חוויית המשתמש ואת היעילות של אחזור הנתונים.
8. מעולה!
השתמשתם בספריית FHIR Engine כדי לנהל משאבי FHIR באפליקציה:
- שימוש ב-Sync API כדי לסנכרן משאבי FHIR עם שרת FHIR
- שימוש ב-Data Access API ליצירה, לקריאה, לעדכון ולמחיקה של משאבי FHIR מקומיים
- שימוש ב-Search API לחיפוש משאבי FHIR מקומיים
מה עסקנו בו
- איך מגדירים שרת HAPI FHIR מקומי
- איך מעלים נתוני בדיקה לשרת המקומי של HAPI FHIR
- איך יוצרים אפליקציה ל-Android באמצעות ספריית FHIR Engine
- איך משתמשים ב-Sync API, ב-Data Access API וב-Search API בספריית FHIR Engine
השלבים הבאים
- עיינו במסמכי העזרה של ספריית FHIR Engine
- תכונות מתקדמות של Search API
- שימוש בספריית FHIR Engine באפליקציה ל-Android