1. قبل البدء
ما الذي ستقوم ببنائه
في هذا الدرس التطبيقي حول الترميز، ستنشئ تطبيق Android باستخدام مكتبة FHIR Engine. سيستخدم تطبيقك مكتبة FHIR Engine لتنزيل موارد FHIR من خادم FHIR وتحميل أي تغييرات محلية إلى الخادم.
ما ستتعرَّف عليه
- كيفية إنشاء خادم HAPI FHIR محلي باستخدام Docker
- كيفية دمج FHIR Engine Library في تطبيق Android
- كيفية استخدام Sync API لإعداد مهمة لمرة واحدة أو دورية لتنزيل موارد FHIR وتحميلها
- كيفية استخدام Search API
- كيفية استخدام واجهات برمجة التطبيقات Data Access API لإنشاء موارد FHIR وقراءتها وتحديثها وحذفها محليًا
المتطلبات
- Docker (الحصول على Docker)
- إصدار حديث من استوديو Android (الإصدار 4.1.2 والإصدارات الأحدث)
- محاكي Android أو جهاز 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_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 كنتيجة بحث بعددtotal
.
3- إعداد تطبيق Android
تنزيل الرمز
لتنزيل الرمز الخاص بهذا الدرس التطبيقي حول الترميز، عليك استنساخ مستودع حزمة تطوير البرامج (SDK) FHIR لنظام التشغيل Android: git clone https://github.com/google/android-fhir.git
.
يمكنك العثور على مشروع المبتدئين لهذا الدرس التطبيقي حول الترميز في codelabs/engine
.
استيراد التطبيق إلى "استوديو Android"
سنبدأ باستيراد تطبيق المبتدئين إلى "استوديو Android".
افتح "استوديو Android" واختَر استيراد مشروع (Gradle أو Eclipse ADT أو غير ذلك) واختَر مجلد codelabs/engine/
من رمز المصدر الذي نزّلته سابقًا.
مزامنة مشروعك مع ملفات Gradle
للتيسير عليك، تمت إضافة تبعيات مكتبة FHIR Engine إلى المشروع. يتيح لك ذلك دمج FHIR Engine Library في تطبيقك. لاحظ السطور التالية حتى نهاية ملف app/build.gradle.kts
الخاص بمشروعك:
dependencies {
// ...
implementation("com.google.android.fhir:engine:0.1.0-beta05")
}
وللتأكد من أن جميع التبعيات متاحة لتطبيقك، يجب عليك مزامنة مشروعك مع ملفات Gradle في هذه المرحلة.
اختَر مزامنة المشروع مع ملفات Gradle () من شريط أدوات "استوديو Android". يمكنك أيضًا تشغيل التطبيق مرة أخرى للتحقق من عمل التبعيات بشكل صحيح.
تشغيل تطبيق إجراء التفعيل
بعد أن استوردت المشروع إلى "استوديو Android"، أصبحت جاهزًا لتشغيل التطبيق لأول مرة.
ابدأ تشغيل محاكي "استوديو Android"، ثم انقر على "تشغيل" () في شريط أدوات "استوديو Android".
4. إنشاء مثيل FHIR Engine
لدمج FHIR Engine في تطبيق Android، ستحتاج إلى استخدام مكتبة FHIR Engine وبدء نسخة من محرك FHIR. سترشدك الخطوات الموضحة أدناه خلال هذه العملية.
- انتقِل إلى فئة التطبيق، وهي في هذا المثال
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
محجوز خصيصًا للمضيف المحلي الذي يمكن الوصول إليه من محاكي 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) }
- في نموذج ViewModel،
PatientListViewModel.kt
، عليك إعداد آلية مزامنة لمرة واحدة. ابحث عن هذا الرمز وأضِفه إلى الدالةtriggerOneTimeSync()
:
يبدأ الكوروتين هذا مزامنة لمرة واحدة مع خادم 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
.
تقوم هذه التعليمات البرمجية بتشغيل الكوروتين داخل نطاق View Model وإعداد محرك FHIR.viewModelScope.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
.
لدينا الآن قائمتان للمرضى - إحداهما من ويكفيلد والأخرى من تاونتون.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
. سنضيف التعليمة البرمجية إلى هذه الدالة.
لفلترة النتائج استنادًا إلى طلب البحث عن الاسم المقدَّم، وإرسال النتائج كي يتم تحديث واجهة المستخدم، عليك دمج مجموعة الرموز الشرطية التالية:
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: اختبار وظائف "بحث Google" الجديدة
- إعادة تشغيل التطبيق:بعد إجراء هذه التغييرات، يجب إعادة إنشاء تطبيقك وتشغيله.
- البحث عن المرضى: في شاشة قائمة المرضى، يمكنك استخدام وظيفة البحث. من المفترض أن تتمكن الآن من إدخال اسم (أو جزء من اسم) لفلترة قائمة المرضى وفقًا لذلك.
بعد استكمال هذه الخطوات، تكون قد حسّنت تطبيقك من خلال تزويد المستخدمين بإمكانية البحث بكفاءة عن المرضى بأسمائهم. ويمكن أن يؤدي ذلك إلى تحسين تجربة المستخدم والكفاءة في استرجاع البيانات بشكلٍ كبير.
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