1. Antes de comenzar
Qué compilarás
En este codelab, compilarás una app para Android con la biblioteca de FHIR Engine. La app usará la biblioteca de FHIR Engine para descargar recursos de FHIR de un servidor de FHIR y subir los cambios locales al servidor.
Qué aprenderás
- Cómo crear un servidor FHIR local de HAPI con Docker
- Cómo integrar la biblioteca de FHIR Engine a tu aplicación para Android
- Cómo usar la API de Sync para configurar un trabajo único o periódico para descargar y subir recursos de FHIR
- Cómo usar la API de búsqueda
- Cómo usar las APIs de acceso a datos para crear, leer, actualizar y borrar recursos FHIR de forma local
Requisitos
- Docker (obtener Docker)
- Una versión reciente de Android Studio (v4.1.2 y versiones posteriores)
- Android Emulator o un dispositivo Android físico que ejecute Android 7.0 Nougat o una versión posterior
- El código de muestra
- Conocimientos básicos sobre el desarrollo de Android en Kotlin
Si es la primera vez que creas apps para Android, puedes comenzar por compilar tu primera app.
2. Configura un servidor FHIR local de HAPI con datos de prueba
HAPI FHIR es un servidor FHIR de código abierto popular. En nuestro codelab, usamos un servidor FHIR local de HAPI para que la app para Android nos conecte.
Configura el servidor FHIR local de HAPI
- Ejecuta el siguiente comando en una terminal para obtener la imagen más reciente de FHIR de HAPI
docker pull hapiproject/hapi:latest
- Crea un contenedor de FHIR de HAPI mediante Docker Desktop para ejecutar la imagen descargada anteriormente
hapiproject/hapi
o ejecuta el siguiente comando:
Más informacióndocker run -p 8080:8080 hapiproject/hapi:latest
- Para inspeccionar el servidor, abre la URL
http://localhost:8080/
en un navegador. Deberías ver la interfaz web de FHIR HAPI.
Propaga el servidor de FHIR local de HAPI con datos de prueba
Para probar nuestra aplicación, necesitaremos algunos datos de prueba en el servidor. Usaremos datos sintéticos que genera Synthea.
- En primer lugar, debemos descargar los datos de muestra de synthea-samples. Descarga y extrae
synthea_sample_data_fhir_r4_sep2019.zip
. Los datos de muestra descomprimidos tienen varios archivos.json
, cada uno de los cuales es un paquete de transacciones para un paciente individual. - Subiremos los datos de las pruebas de tres pacientes al servidor FHIR local de HAPI. Ejecuta el siguiente comando en el directorio que contiene los archivos 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/
- Para subir los datos de prueba de todos los pacientes al servidor, ejecuta
Sin embargo, esto puede tardar mucho tiempo en completarse y no es necesario en el codelab.for f in *.json; do curl -X POST -H "Content-Type: application/json" -d @$f http://localhost:8080/fhir/ ; done
- Para verificar que los datos de prueba estén disponibles en el servidor, abre la URL
http://localhost:8080/fhir/Patient/
en un navegador. Deberías ver el textoHTTP 200 OK
y la secciónResponse Body
de la página, que contiene datos de pacientes en un paquete de FHIR, como resultado de la búsqueda con un recuento detotal
.
3. Configura la app para Android
Cómo descargar el código
Para descargar el código de este codelab, clona el repositorio del SDK de FHIR de Android: git clone https://github.com/google/android-fhir.git
El proyecto inicial de este codelab se encuentra en codelabs/engine
.
Importa la app a Android Studio
Comenzamos importando la app de partida a Android Studio.
Abre Android Studio, selecciona Import Project (Gradle, Eclipse ADT, etc.) y elige la carpeta codelabs/engine/
del código fuente que descargaste antes.
Sincroniza tu proyecto con archivos Gradle
Para tu comodidad, las dependencias de la biblioteca de FHIR Engine ya se agregaron al proyecto. Esto te permite integrar la biblioteca de FHIR Engine en tu app. Observa las siguientes líneas al final del archivo app/build.gradle.kts
de tu proyecto:
dependencies {
// ...
implementation("com.google.android.fhir:engine:0.1.0-beta05")
}
A fin de asegurarte de que todas las dependencias estén disponibles para tu app, debes sincronizar tu proyecto con archivos de Gradle en este momento.
Selecciona Sync Project with Gradle Files () en la barra de herramientas de Android Studio. También puedes volver a ejecutar la app para comprobar que las dependencias funcionen correctamente.
Ejecuta la app de partida
Ahora que importaste el proyecto a Android Studio, podrás ejecutar la app por primera vez.
Inicia el emulador de Android Studio y haz clic en Run () en la barra de herramientas de Android Studio.
4. Crear instancia de FHIR Engine
Si quieres incorporar el motor de FHIR a tu app para Android, deberás usar la biblioteca de FHIR Engine y, luego, iniciar una instancia del motor de FHIR. Los pasos que se describen a continuación te guiarán a lo largo del proceso.
- Navega a la clase Application, que en este ejemplo es
FhirApplication.kt
, ubicada enapp/src/main/java/com/google/android/fhir/codelabs/engine
. - Dentro del método
onCreate()
, agrega el siguiente código para inicializar FHIR Engine:
Notas: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
: Habilita la encriptación de datos si el dispositivo lo admite.RECREATE_AT_OPEN
: Determina la estrategia de error de la base de datos. En este caso, vuelve a crear la base de datos si se produce un error al momento de abrirla.baseUrl
enServerConfiguration
: Esta es la URL base del servidor de FHIR. La dirección IP proporcionada (10.0.2.2
) está especialmente reservada para localhost, al que se puede acceder desde el emulador de Android. Obtén más información.
- En la clase
FhirApplication
, agrega la siguiente línea para crear una instancia de FHIR Engine de forma diferida:
Esto garantiza que la instancia de FhirEngine solo se cree cuando se accede a ella por primera vez, no inmediatamente cuando se inicia la app.private val fhirEngine: FhirEngine by lazy { FhirEngineProvider.getInstance(this) }
- Agrega el siguiente método de conveniencia a la clase
FhirApplication
para facilitar el acceso en toda tu aplicación:
Este método estático te permite recuperar la instancia de FHIR Engine desde cualquier lugar de la aplicación usando el contexto.companion object { fun fhirEngine(context: Context) = (context.applicationContext as FhirApplication).fhirEngine }
5. Sincronizar datos con el servidor de FHIR
- Crea una clase
DownloadWorkManagerImpl.kt
nueva. En esta clase, definirás cómo la aplicación recuperará el siguiente recurso de la lista para descargar:
Esta clase tiene una cola de tipos de recursos que quiere descargar. Procesa respuestas y extrae los recursos del paquete que se muestra, que se guardan en la base de datos local.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 } }
- Crear una clase nueva
AppFhirSyncWorker.kt
Esta clase define cómo se sincronizará la app con el servidor remoto FHIR mediante un trabajador en segundo plano.
Aquí definimos qué administrador de descargas, agente de resolución de conflictos e instancia de motor de FHIR se usará para la sincronización.class AppFhirSyncWorker(appContext: Context, workerParams: WorkerParameters) : FhirSyncWorker(appContext, workerParams) { override fun getDownloadWorkManager() = DownloadWorkManagerImpl() override fun getConflictResolver() = AcceptLocalConflictResolver override fun getFhirEngine() = FhirApplication.fhirEngine(applicationContext) }
- En tu ViewModel,
PatientListViewModel.kt
, configurarás un mecanismo de sincronización único. Ubica y agrega este código a la funcióntriggerOneTimeSync()
:
Esta corrutina inicia una sincronización única con el servidor de FHIR mediante el AppFhirSyncWorker que definimos anteriormente. Luego, actualizará la IU en función del estado del proceso de sincronización.viewModelScope.launch { Sync.oneTimeSync<AppFhirSyncWorker>(getApplication()) .shareIn(this, SharingStarted.Eagerly, 10) .collect { _pollState.emit(it) } }
- En el archivo
PatientListFragment.kt
, actualiza el cuerpo de la funciónhandleSyncJobStatus
:
Aquí, cuando finalice el proceso de sincronización, se mostrará un mensaje de aviso en el que se notificará al usuario y, luego, la app mostrará a todos los pacientes invocando una búsqueda con un nombre vacío.when (syncJobStatus) { is SyncJobStatus.Finished -> { Toast.makeText(requireContext(), "Sync Finished", Toast.LENGTH_SHORT).show() viewModel.searchPatientsByName("") } else -> {} }
Ahora que todo está configurado, ejecuta tu app. Haz clic en el botón Sync
en el menú. Si todo funciona correctamente, deberías ver que los pacientes de tu servidor FHIR local se descargan y se muestran en la aplicación.
6. Modifica y sube datos de pacientes
En esta sección, te ayudaremos a modificar los datos de los pacientes en función de criterios específicos y a subir los datos actualizados al servidor FHIR. Específicamente, cambiaremos las ciudades de las direcciones por los pacientes que residen en Wakefield
y Taunton
.
Paso 1: Configura la lógica de modificación en PatientListViewModel
El código de esta sección se agrega a la función triggerUpdate
en PatientListViewModel
- Accede al motor de FHIR:Para comenzar, obtén una referencia al motor de FHIR en
PatientListViewModel.kt
.
Este código inicia una corrutina dentro del alcance del ViewModel e inicializa el motor de FHIR.viewModelScope.launch { val fhirEngine = FhirApplication.fhirEngine(getApplication())
- Buscar pacientes en Wakefield:Usa el motor FHIR para buscar pacientes cuya dirección sea
Wakefield
.
Aquí, usamos el métodoval patientsFromWakefield = fhirEngine.search<Patient> { filter( Patient.ADDRESS_CITY, { modifier = StringFilterModifier.MATCHES_EXACTLY value = "Wakefield" } ) }
search
del motor de FHIR para filtrar a los pacientes según la ciudad de su dirección. El resultado será una lista de pacientes de Wakefield. - Búsqueda de pacientes en Taunton:Del mismo modo, busca pacientes cuya dirección sea
Taunton
.
Ahora tenemos dos listas de pacientes: una de Wakefield y otra de Taunton.val patientsFromTaunton = fhirEngine.search<Patient> { filter( Patient.ADDRESS_CITY, { modifier = StringFilterModifier.MATCHES_EXACTLY value = "Taunton" } ) }
- Modificar las direcciones de los pacientes:Desplázate por cada paciente de la lista
patientsFromWakefield
, cambia su ciudad aTaunton
y actualízalas en el motor de FHIR.
Del mismo modo, actualiza cada paciente de la listapatientsFromWakefield.forEach { it.resource.address.first().city = "Taunton" fhirEngine.update(it.resource) }
patientsFromTaunton
para que su ciudad cambie aWakefield
.patientsFromTaunton.forEach { it.resource.address.first().city = "Wakefield" fhirEngine.update(it.resource) }
- Iniciar la sincronización:Después de modificar los datos de forma local, activa una sincronización única para asegurarte de que los datos se actualicen en el servidor de FHIR.
La llave de cierretriggerOneTimeSync() }
}
indica el final de la corrutina que se inició al principio.
Paso 2: Prueba la funcionalidad
- Pruebas de la IU:Ejecuta tu app. Haz clic en el botón
Update
del menú. Deberías ver las ciudades de dirección de los pacientesAaron697
yAbby752
intercambiadas. - Verificación del servidor:Abre un navegador y navega hasta
http://localhost:8080/fhir/Patient/
. Verifica que la ciudad de la dirección de los pacientesAaron697
yAbby752
esté actualizada en el servidor FHIR local.
Con estos pasos, implementaste correctamente un mecanismo para modificar los datos de los pacientes y sincronizar los cambios con tu servidor de FHIR.
7. Buscar pacientes por nombre
La búsqueda de pacientes por su nombre puede proporcionar una forma fácil de recuperar información. Aquí, lo guiaremos a través del proceso de implementación de esta función en su aplicación.
Paso 1: Actualiza la firma de la función
Navega a tu archivo PatientListViewModel.kt
y busca la función llamada searchPatientsByName
. Agregaremos código a esta función.
Para filtrar los resultados en función de la consulta de nombre proporcionada y emitir los resultados para que la IU se actualice, incorpora el siguiente bloque de código condicional:
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 }
}
}
Aquí, si nameQuery
no está vacío, la función de búsqueda filtrará los resultados para incluir solo pacientes cuyos nombres contengan la consulta especificada.
Paso 2: Prueba la nueva función de búsqueda
- Reinicia la app:Después de realizar estos cambios, vuelve a compilar y ejecuta tu app.
- Search for Patients: En la pantalla de la lista de pacientes, usa la función de búsqueda. Ahora deberías poder ingresar un nombre (o parte de él) para filtrar la lista de pacientes según corresponda.
Con estos pasos completados, mejoras tu aplicación, ya que les ofreces a los usuarios la capacidad de buscar pacientes de manera eficiente por sus nombres. Esto puede mejorar significativamente la experiencia del usuario y la eficiencia en la recuperación de datos.
8. ¡Felicitaciones!
Usaste la biblioteca de FHIR Engine para administrar los recursos de FHIR en tu aplicación:
- Usa la API de Sync para sincronizar los recursos de FHIR con un servidor de FHIR
- Usa la API de Data Access para crear, leer, actualizar y borrar recursos de FHIR locales
- Usa la API de búsqueda para buscar recursos de FHIR locales
Temas abordados
- Cómo configurar un servidor FHIR local de HAPI
- Cómo subir datos de prueba al servidor de FHIR local de HAPI
- Cómo compilar una app para Android con la biblioteca de FHIR Engine
- Cómo usar la API de Sync, la API de acceso a datos y la API de búsqueda en la biblioteca del motor de FHIR
Próximos pasos
- Explorar la documentación de la biblioteca de FHIR Engine
- Explora las funciones avanzadas de la API de búsqueda
- Aplica la biblioteca de FHIR Engine en tu propia app para Android