1. Antes de começar
O que você vai criar
Neste codelab, você vai criar um app Android usando a biblioteca FHIR Engine. O app vai usar a biblioteca FHIR Engine para fazer o download de recursos do FHIR de um servidor FHIR e fazer upload de todas as mudanças locais para o servidor.
O que você vai aprender
- Como criar um servidor HAPI FHIR local usando o Docker
- Como integrar a biblioteca FHIR Engine ao seu aplicativo Android
- Como usar a API Sync para configurar um job único ou periódico para fazer o download e o upload de recursos do FHIR
- Como usar a API Search
- Como usar as APIs de acesso a dados para criar, ler, atualizar e excluir recursos FHIR localmente
O que é necessário
- Docker (get Docker)
- Uma versão recente do Android Studio (v4.1.2+).
- Android Emulator ou um dispositivo Android físico com o Android 7.0 Nougat ou mais recente
- Código de amostra
- Conhecimento básico de desenvolvimento para Android em Kotlin
Se você ainda não criou apps Android, comece criando seu primeiro app.
2. Configurar um servidor local do HAPI FHIR com dados de teste
O HAPI FHIR é um servidor FHIR de código aberto conhecido. Usamos um servidor HAPI FHIR local no nosso codelab para que o app Android se conecte.
Configurar o servidor local do HAPI FHIR
- Execute o seguinte comando em um terminal para receber a imagem mais recente do HAPI FHIR.
docker pull hapiproject/hapi:latest
- Crie um contêiner HAPI FHIR usando o Docker Desktop para executar a imagem
hapiproject/hapi
do download anterior ou execute o seguinte comando: Saiba mais.docker run -p 8080:8080 hapiproject/hapi:latest
- Inspecione o servidor abrindo o URL
http://localhost:8080/
em um navegador. A interface da Web do HAPI FHIR vai aparecer.
Preencher o servidor local do HAPI FHIR com dados de teste
Para testar nosso aplicativo, precisamos de alguns dados de teste no servidor. Vamos usar dados sintéticos gerados pelo Synthea.
- Primeiro, precisamos fazer o download de dados de exemplo do synthea-samples. Faça o download e extraia
synthea_sample_data_fhir_r4_sep2019.zip
. Os dados de amostra descompactados têm vários arquivos.json
, cada um deles é um pacote de transações para um paciente individual. - Vamos fazer upload dos dados de teste de três pacientes para o servidor local do HAPI FHIR. Execute o seguinte comando no diretório que contém arquivos 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 fazer upload dos dados de teste de todos os pacientes para o servidor, execute
No entanto, isso pode levar muito tempo para ser concluído e não é necessário para o codelab.for f in *.json; do curl -X POST -H "Content-Type: application/json" -d @$f http://localhost:8080/fhir/ ; done
- Abra o URL
http://localhost:8080/fhir/Patient/
em um navegador para verificar se os dados de teste estão disponíveis no servidor. O textoHTTP 200 OK
e a seçãoResponse Body
da página que contém dados do paciente em um pacote FHIR aparecem como o resultado da pesquisa com uma contagemtotal
.
3. Configurar o app Android
Fazer o download do código
Para fazer o download do código deste codelab, clone o repositório do SDK FHIR do Android: git clone https://github.com/google/android-fhir.git
O projeto inicial deste codelab está localizado em codelabs/engine
.
Importar o app para o Android Studio
Começamos importando o app inicial no Android Studio.
Abra o Android Studio, selecione Import Project (Gradle, Eclipse ADT, etc.) e escolha a pasta codelabs/engine/
do código-fonte que você salvou anteriormente.
Sincronizar o projeto com arquivos do Gradle
Para sua conveniência, as dependências da biblioteca do mecanismo FHIR já foram adicionadas ao projeto. Isso permite integrar a biblioteca FHIR Engine ao app. Observe as linhas a seguir até o final do arquivo app/build.gradle.kts
do projeto:
dependencies {
// ...
implementation("com.google.android.fhir:engine:1.1.0")
}
Para garantir que todas as dependências estejam disponíveis para o app, sincronize o projeto com os arquivos do Gradle.
Selecione Sync Project with Gradle Files () na barra de ferramentas do Android Studio. Você também pode executar o app novamente para verificar se as dependências estão funcionando corretamente.
Executar o app inicial
Agora que você importou o projeto para o Android Studio, está tudo pronto para executar o app pela primeira vez.
Inicie o emulador do Android Studio e clique em Executar () na barra de ferramentas do Android Studio.
4. Criar uma instância do FHIR Engine
Para incorporar o FHIR Engine ao seu app Android, use a biblioteca FHIR Engine e inicie uma instância dele. As etapas descritas abaixo vão orientar você durante o processo.
- Navegue até a classe do aplicativo, que neste exemplo é
FhirApplication.kt
, localizada emapp/src/main/java/com/google/android/fhir/codelabs/engine
. - No método
onCreate()
, adicione o seguinte código para inicializar o mecanismo FHIR: Observações: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
: ativa a criptografia de dados, se o dispositivo oferecer suporte a ela.RECREATE_AT_OPEN
: determina a estratégia de erro do banco de dados. Nesse caso, o banco de dados é recriado se ocorrer um erro na abertura.baseUrl
emServerConfiguration
: é o URL base do servidor FHIR. O endereço IP10.0.2.2
fornecido é reservado especialmente para localhost, acessível pelo emulador do Android. Saiba mais.
- Na classe
FhirApplication
, adicione a linha a seguir para instanciar de forma preguiçosa o mecanismo FHIR: Isso garante que a instância do FhirEngine seja criada apenas quando for acessada pela primeira vez, e não imediatamente quando o app for iniciado.private val fhirEngine: FhirEngine by lazy { FhirEngineProvider.getInstance(this) }
- Adicione o seguinte método de conveniência à classe
FhirApplication
para facilitar o acesso em todo o aplicativo: Esse método estático permite recuperar a instância do mecanismo FHIR em qualquer lugar do app usando o contexto.companion object { fun fhirEngine(context: Context) = (context.applicationContext as FhirApplication).fhirEngine }
5. Sincronizar dados com o servidor FHIR
- Crie uma nova classe
DownloadWorkManagerImpl.kt
. Nesta classe, você vai definir como o aplicativo busca o próximo recurso da lista para fazer o download: Essa classe tem uma fila de tipos de recursos que ela quer fazer o download. Ele processa as respostas e extrai os recursos do pacote retornado, que são salvos no banco de dados 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 } }
- Crie uma nova classe
AppFhirSyncWorker.kt
. Essa classe define como o app vai ser sincronizado com o servidor FHIR remoto usando um worker em segundo plano. Neste exemplo, definimos qual gerenciador de downloads, solucionador de conflitos e instância do mecanismo FHIR usar para a sincronização.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, ) }
- No ViewModel,
PatientListViewModel.kt
, você vai configurar um mecanismo de sincronização único. Localize e adicione este código à funçãotriggerOneTimeSync()
: Essa co-rotina inicia uma sincronização única com o servidor FHIR usando o AppFhirSyncWorker que definimos anteriormente. Em seguida, ele vai atualizar a interface com base no estado do processo de sincronização.viewModelScope.launch { Sync.oneTimeSync<AppFhirSyncWorker>(getApplication()) .shareIn(this, SharingStarted.Eagerly, 10) .collect { _pollState.emit(it) } }
- No arquivo
PatientListFragment.kt
, atualize o corpo da funçãohandleSyncJobStatus
: Nesse caso, quando o processo de sincronização for concluído, uma mensagem de aviso vai aparecer para notificar o usuário, e o app vai mostrar todos os pacientes ao invocar uma pesquisa com um nome vazio.when (syncJobStatus) { is SyncJobStatus.Finished -> { Toast.makeText(requireContext(), "Sync Finished", Toast.LENGTH_SHORT).show() viewModel.searchPatientsByName("") } else -> {} }
Agora que tudo está configurado, execute o app. Clique no botão Sync
no menu. Se tudo funcionar corretamente, os pacientes do seu servidor FHIR local serão transferidos por download e exibidos no aplicativo.
6. Modificar e enviar dados do paciente
Nesta seção, vamos orientar você no processo de modificar os dados do paciente com base em critérios específicos e fazer o upload dos dados atualizados para o servidor FHIR. Mais especificamente, vamos trocar as cidades de endereço dos pacientes que moram em Wakefield
e Taunton
.
Etapa 1: configurar a lógica de modificação em PatientListViewModel
O código desta seção é adicionado à função triggerUpdate
em PatientListViewModel
.
- Acessar o mecanismo FHIR:comece acessando uma referência ao mecanismo FHIR no
PatientListViewModel.kt
. Esse código inicia uma corrotina no escopo do ViewModel e inicializa o mecanismo FHIR.viewModelScope.launch { val fhirEngine = FhirApplication.fhirEngine(getApplication())
- Pesquisar pacientes de Wakefield:use o mecanismo FHIR para pesquisar pacientes com uma cidade de endereço
Wakefield
. Neste exemplo, usamos o métodoval patientsFromWakefield = fhirEngine.search<Patient> { filter( Patient.ADDRESS_CITY, { modifier = StringFilterModifier.MATCHES_EXACTLY value = "Wakefield" } ) }
search
do mecanismo FHIR para filtrar pacientes com base na cidade do endereço. O resultado será uma lista de pacientes de Wakefield. - Pesquisar pacientes de Taunton:da mesma forma, pesquise pacientes com um endereço na cidade de
Taunton
. Agora temos duas listas de pacientes: uma de Wakefield e outra de Taunton.val patientsFromTaunton = fhirEngine.search<Patient> { filter( Patient.ADDRESS_CITY, { modifier = StringFilterModifier.MATCHES_EXACTLY value = "Taunton" } ) }
- Modificar os endereços dos pacientes:analise cada paciente na lista
patientsFromWakefield
, mude a cidade paraTaunton
e atualize no mecanismo FHIR. Da mesma forma, atualize cada paciente na listapatientsFromWakefield.forEach { it.resource.address.first().city = "Taunton" fhirEngine.update(it.resource) }
patientsFromTaunton
para mudar a cidade paraWakefield
.patientsFromTaunton.forEach { it.resource.address.first().city = "Wakefield" fhirEngine.update(it.resource) }
- Iniciar a sincronização:depois de modificar os dados localmente, acione uma sincronização única para garantir que os dados sejam atualizados no servidor FHIR.
A chave de fechamentotriggerOneTimeSync() }
}
indica o fim da corrotina iniciada no início.
Etapa 2: testar a funcionalidade
- Teste de interface:execute o app. Clique no botão
Update
no menu. As cidades de endereço do pacienteAaron697
eAbby752
vão estar trocadas. - Verificação do servidor:abra um navegador e acesse
http://localhost:8080/fhir/Patient/
. Verifique se a cidade do endereço dos pacientesAaron697
eAbby752
foi atualizada no servidor FHIR local.
Ao seguir estas etapas, você implementou um mecanismo para modificar os dados do paciente e sincronizar as mudanças com seu servidor FHIR.
7. Pesquisar pacientes por nome
A pesquisa de pacientes pelo nome pode ser uma maneira fácil de recuperar informações. Aqui, vamos mostrar o processo de implementação desse recurso no seu app.
Etapa 1: atualizar a assinatura da função
Navegue até o arquivo PatientListViewModel.kt
e encontre a função com o nome searchPatientsByName
. Vamos adicionar código a essa função.
Para filtrar os resultados com base na consulta de nome fornecida e emitir os resultados para a atualização da interface, incorpore o seguinte bloco 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 }
}
}
Aqui, se o nameQuery
não estiver vazio, a função de pesquisa vai filtrar os resultados para incluir apenas os pacientes cujos nomes contêm a consulta especificada.
Etapa 2: testar a nova funcionalidade de pesquisa
- Reinicie o app:depois de fazer essas mudanças, recrie e execute o app.
- Pesquisar pacientes: na tela da lista de pacientes, use a funcionalidade de pesquisa. Agora você pode inserir um nome (ou parte dele) para filtrar a lista de pacientes.
Com essas etapas concluídas, você melhorou seu aplicativo, permitindo que os usuários pesquisem pacientes de forma eficiente pelo nome. Isso pode melhorar significativamente a experiência do usuário e a eficiência na recuperação de dados.
8. Parabéns!
Você usou a biblioteca FHIR Engine para gerenciar recursos FHIR no seu app:
- Usar a API Sync para sincronizar recursos FHIR com um servidor FHIR
- Usar a API Data Access para criar, ler, atualizar e excluir recursos locais do FHIR
- Usar a API Search para pesquisar recursos FHIR locais
O que aprendemos
- Como configurar um servidor local do HAPI FHIR
- Como fazer upload de dados de teste para o servidor local do HAPI FHIR
- Como criar um app Android usando a biblioteca FHIR Engine
- Como usar a API Sync, a API Data Access e a API Search na biblioteca FHIR Engine
Próximas etapas
- Acesse a documentação da biblioteca FHIR Engine
- Conheça os recursos avançados da API Search
- Aplicar a biblioteca FHIR Engine no seu próprio app Android