1. 事前準備
建構項目
在本程式碼研究室中,您將使用 FHIR Engine 程式庫建構 Android 應用程式。您的應用程式會使用 FHIR Engine 程式庫,從 FHIR 伺服器下載 FHIR 資源,並將任何本機變更上傳至伺服器。
課程內容
- 如何使用 Docker 建立本機 HAPI FHIR 伺服器
- 如何將 FHIR Engine 程式庫整合至 Android 應用程式
- 如何使用 Sync API 設定一次性或定期工作,以便下載及上傳 FHIR 資源
- 如何使用 Search API
- 如何使用資料存取 API 在本機建立、讀取、更新及刪除 FHIR 資源
軟硬體需求
- Docker (取得 Docker)
- 最新版 Android Studio (4.1.2 以上版本)
- Android Emulator 或搭載 Android 7.0 Nougat 以上版本的實體 Android 裝置
- 程式碼範例
- 對 Kotlin 中的 Android 開發作業有基本瞭解
如果您之前未建構過 Android 應用程式,可以先建構第一個應用程式。
2. 設定本機 HAPI FHIR 伺服器,並加入測試資料
HAPI FHIR 是熱門的開放原始碼 FHIR 伺服器。我們在程式碼研究室中使用本機 HAPI FHIR 伺服器,供 Android 應用程式連線。
設定本機 HAPI FHIR 伺服器
- 在終端機中執行下列指令,取得 HAPI FHIR 的最新映像檔
docker pull hapiproject/hapi:latest
- 使用 Docker Desktop 執行先前下載的映像檔
hapiproject/hapi
,或執行下列指令,建立 HAPI FHIR 容器 瞭解詳情。docker run -p 8080:8080 hapiproject/hapi:latest
- 在瀏覽器中開啟網址
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
- 在瀏覽器中開啟網址
http://localhost:8080/fhir/Patient/
,確認伺服器上有測試資料。您應該會看到文字HTTP 200 OK
和Response Body
部分,其中包含 FHIR 束帶中的病患資料,並以total
計數的搜尋結果。
3. 設定 Android 應用程式
下載程式碼
如要下載本程式碼研究室的程式碼,請複製 Android FHIR SDK 存放區:git clone https://github.com/google/android-fhir.git
這個程式碼研究室的範例專案位於 codelabs/engine
中。
將應用程式匯入 Android Studio
首先,我們會將範例應用程式匯入 Android Studio。
開啟 Android Studio,選取「Import Project (Gradle, Eclipse ADT, etc.)」,然後從先前下載的來源程式碼中選擇 codelabs/engine/
資料夾。
將專案與 Gradle 檔案同步處理
為方便起見,我們已將 FHIR Engine Library 依附元件新增至專案。這樣一來,您就能在應用程式中整合 FHIR Engine 程式庫。請觀察專案 app/build.gradle.kts
檔案結尾的以下行程式碼:
dependencies {
// ...
implementation("com.google.android.fhir:engine:1.1.0")
}
為確保應用程式可使用所有依附元件,您應在此時將專案與 Gradle 檔案同步。
在 Android Studio 工具列中選取「Sync Project with Gradle Files」 ()。您也可以再次執行應用程式,檢查依附元件是否正常運作。
執行範例應用程式
專案已匯入 Android Studio,您可以開始執行應用程式。
啟動 Android Studio 模擬器,然後按一下 Android Studio 工具列中的「Run」(執行) ()。
4. 建立 FHIR Engine 例項
如要將 FHIR Engine 整合至 Android 應用程式,您必須使用 FHIR Engine 程式庫並啟動 FHIR Engine 的例項。請按照下列步驟完成程序。
- 前往「Application」類別,在本例中為
app/src/main/java/com/google/android/fhir/codelabs/engine
中的FhirApplication.kt
。 - 在
onCreate()
方法中加入下列程式碼,初始化 FHIR 引擎: 注意事項: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
:決定資料庫錯誤策略。在這種情況下,如果開啟時發生錯誤,系統就會重新建立資料庫。ServerConfiguration
中的baseUrl
:這是 FHIR 伺服器的基準網址。提供的 IP 位址10.0.2.2
是專門為 localhost 保留,可透過 Android 模擬器存取。瞭解詳情。
- 在
FhirApplication
類別中,新增下列程式碼,以便延遲實例化 FHIR 引擎: 這可確保 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()
函式: 這個協同程式會使用我們先前定義的 AppFhirSyncWorker,與 FHIR 伺服器啟動一次性同步處理作業。接著,系統會根據同步處理程序的狀態更新 UI。viewModelScope.launch { Sync.oneTimeSync<AppFhirSyncWorker>(getApplication()) .shareIn(this, SharingStarted.Eagerly, 10) .collect { _pollState.emit(it) } }
- 在
PatientListFragment.kt
檔案中,更新handleSyncJobStatus
函式的主體: 在這個範例中,同步處理程序完成後,系統會顯示 Toast 訊息通知使用者,然後應用程式會呼叫空白名稱的搜尋,並顯示所有病患。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 中設定修改邏輯
本節中的程式碼會新增至 PatientListViewModel
中的 triggerUpdate
函式
- 存取 FHIR 引擎:請先取得
PatientListViewModel.kt
中的 FHIR 引擎參照。 這段程式碼會在 ViewModel 範圍內啟動協同程式,並初始化 FHIR 引擎。viewModelScope.launch { val fhirEngine = FhirApplication.fhirEngine(getApplication())
- 搜尋 Wakefield 的病患:使用 FHIR 引擎搜尋地址城市為
Wakefield
的病患。 我們在這裡使用 FHIR 引擎的val patientsFromWakefield = fhirEngine.search<Patient> { filter( Patient.ADDRESS_CITY, { modifier = StringFilterModifier.MATCHES_EXACTLY value = "Wakefield" } ) }
search
方法,根據病患的地址所在城市篩選病患。結果會是 Wakefield 的病患清單。 - 搜尋 Taunton 的病患:同樣地,搜尋地址城市為
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() }
}
表示一開始啟動的協同程式已結束。
步驟 2:測試功能
- 使用者介面測試:執行應用程式。按一下選單中的
Update
按鈕。您應該會看到病患Aaron697
和Abby752
的地址城市互換。 - 伺服器驗證:開啟瀏覽器並前往
http://localhost:8080/fhir/Patient/
。確認患者Aaron697
和Abby752
的地址城市已在本機 FHIR 伺服器上更新。
按照這些步驟操作後,您已成功實作修改病患資料的機制,並將變更內容同步處理至 FHIR 伺服器。
7. 依名稱搜尋病患
您可以透過患者姓名搜尋,以便於擷取資訊。我們將逐步說明如何在應用程式中實作這項功能。
步驟 1:更新函式簽名
前往 PatientListViewModel.kt
檔案,找出名為 searchPatientsByName
的函式。我們會在這個函式中加入程式碼。
如要根據提供的名稱查詢篩選結果,並發出結果供 UI 更新,請納入下列條件式程式碼區塊:
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 伺服器
- 如何使用 FHIR Engine Library 建構 Android 應用程式
- 如何在 FHIR Engine 程式庫中使用 Sync API、Data Access API 和 Search API
後續步驟
- 探索 FHIR Engine 程式庫的說明文件
- 探索 Search API 的進階功能
- 在自有 Android 應用程式中套用 FHIR Engine 程式庫