เกี่ยวกับ Codelab นี้
1 ก่อนเริ่มต้น
สิ่งที่คุณจะสร้าง
ในโค้ดแล็บนี้ คุณจะได้สร้างแอป Android โดยใช้ไลบรารี FHIR Engine แอปของคุณจะใช้ FHIR Engine Library เพื่อดาวน์โหลดทรัพยากร FHIR จากเซิร์ฟเวอร์ FHIR และอัปโหลดการเปลี่ยนแปลงในเครื่องไปยังเซิร์ฟเวอร์
สิ่งที่คุณจะได้เรียนรู้
- วิธีสร้างเซิร์ฟเวอร์ HAPI FHIR ในพื้นที่โดยใช้ Docker
- วิธีผสานรวมไลบรารี FHIR Engine เข้ากับแอปพลิเคชัน Android
- วิธีใช้ Sync API เพื่อตั้งค่างานแบบครั้งเดียวหรือเป็นระยะเพื่อดาวน์โหลดและอัปโหลดทรัพยากร FHIR
- วิธีใช้ Search API
- วิธีใช้ Data Access API เพื่อสร้าง อ่าน อัปเดต และลบทรัพยากร FHIR ในเครื่อง
สิ่งที่คุณต้องมี
- Docker (รับ Docker)
- Android Studio (v4.1.2 ขึ้นไป) เวอร์ชันล่าสุด
- Android Emulator หรืออุปกรณ์ Android ที่ใช้ Android 7.0 Nougat ขึ้นไป
- โค้ดตัวอย่าง
- ความรู้พื้นฐานเกี่ยวกับการพัฒนาแอป Android ใน Kotlin
หากไม่เคยสร้างแอป Android มาก่อน ให้เริ่มต้นด้วยการสร้างแอปแรก
2 ตั้งค่าเซิร์ฟเวอร์ HAPI FHIR ในพื้นที่ด้วยข้อมูลทดสอบ
HAPI FHIR เป็นเซิร์ฟเวอร์ FHIR แบบโอเพนซอร์สที่ได้รับความนิยม เราใช้เซิร์ฟเวอร์ HAPI FHIR ในพื้นที่ในโค้ดแล็บเพื่อให้แอป 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
จำนวนมาก โดยแต่ละไฟล์จะเป็นกลุ่มธุรกรรมสำหรับผู้ป่วยแต่ละราย - เราจะอัปโหลดข้อมูลทดสอบสำหรับผู้ป่วย 3 รายไปยังเซิร์ฟเวอร์ 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 เลือกนําเข้าโปรเจ็กต์ (Gradle, Eclipse ADT ฯลฯ) แล้วเลือกโฟลเดอร์ codelabs/engine/
จากซอร์สโค้ดที่คุณดาวน์โหลดไว้ก่อนหน้านี้
ซิงค์โปรเจ็กต์กับไฟล์ Gradle
เราได้เพิ่มไลบรารี FHIR Engine ลงในโปรเจ็กต์แล้วเพื่อความสะดวก ซึ่งจะช่วยให้คุณผสานรวมไลบรารี FHIR Engine ในแอปได้ โปรดดูบรรทัดต่อไปนี้จนถึงส่วนท้ายของไฟล์ app/build.gradle.kts
ของโปรเจ็กต์
dependencies {
// ...
implementation("com.google.android.fhir:engine:1.1.0")
}
คุณควรซิงค์โปรเจ็กต์กับไฟล์ Gradle ในตอนนี้เพื่อให้แน่ใจว่าแอปของคุณจะใช้ Dependency ทั้งหมดได้
เลือกซิงค์โปรเจ็กต์กับไฟล์ Gradle () จากแถบเครื่องมือของ Android Studio นอกจากนี้ คุณยังเรียกใช้แอปอีกครั้งเพื่อตรวจสอบว่า Dependency ทํางานอย่างถูกต้องหรือไม่
เรียกใช้แอปเริ่มต้น
เมื่อนําเข้าโปรเจ็กต์ไปยัง 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 ที่อยู่ IP10.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()
โคโรทีนนี้จะเริ่มการซิงค์แบบครั้งเดียวกับเซิร์ฟเวอร์ FHIR โดยใช้ AppFhirSyncWorker ที่เรากําหนดไว้ก่อนหน้านี้ จากนั้นระบบจะอัปเดต UI ตามสถานะของกระบวนการซิงค์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 Engine:เริ่มต้นด้วยการอ้างอิง FHIR Engine ใน
PatientListViewModel.kt
โค้ดนี้จะเปิด coroutine ภายในขอบเขตของ ViewModel และเริ่มต้นการทำงานของเครื่องมือ FHIRviewModelScope.launch {
val fhirEngine = FhirApplication.fhirEngine(getApplication()) - ค้นหาผู้ป่วยจาก Wakefield:ใช้เครื่องมือ FHIR เพื่อค้นหาผู้ป่วยที่มีเมืองในที่อยู่เป็น
Wakefield
ในส่วนนี้ เราใช้เมธอดval patientsFromWakefield =
fhirEngine.search<Patient> {
filter(
Patient.ADDRESS_CITY,
{
modifier = StringFilterModifier.MATCHES_EXACTLY
value = "Wakefield"
}
)
}search
ของเครื่องมือ FHIR เพื่อกรองผู้ป่วยตามเมืองที่อยู่ ผลลัพธ์ที่ได้จะเป็นรายการผู้ป่วยจากเวย์คอล์ด - ค้นหาผู้ป่วยจาก Taunton:ในทํานองเดียวกัน ให้ค้นหาผู้ป่วยที่มีเมืองในที่อยู่เป็น
Taunton
ตอนนี้เรามีรายชื่อผู้ป่วย 2 รายการ รายการหนึ่งจาก Wakefield และอีกรายการหนึ่งจาก Tauntonval 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: ทดสอบฟังก์ชันการทำงาน
- การทดสอบ UI:เรียกใช้แอป คลิกปุ่ม
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 ในพื้นที่
- วิธีสร้างแอป Android โดยใช้ FHIR Engine Library
- วิธีใช้ Sync API, Data Access API และ Search API ในไลบรารี FHIR Engine
ขั้นตอนถัดไป
- สำรวจเอกสารประกอบสำหรับไลบรารี FHIR Engine
- สำรวจฟีเจอร์ขั้นสูงของ Search API
- ใช้ FHIR Engine Library ในแอป Android ของคุณเอง