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 de um servidor FHIR e fazer upload das alterações locais para o servidor.
O que você vai aprender
- Como criar um servidor FHIR HAPI 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 upload de recursos FHIR
- Como usar a API Search
- Como usar as APIs Data Access para criar, ler, atualizar e excluir recursos do FHIR localmente
O que é necessário
- Docker (get Docker)
- Uma versão recente do Android Studio (v4.1.2+)
- Android Emulator ou um dispositivo físico com Android 7.0 Nougat ou mais recente
- Código de amostra
- Conhecimento básico de desenvolvimento para Android em Kotlin.
Se você nunca criou apps Android antes, pode começar criando seu primeiro app.
2. Configurar um servidor FHIR HAPI local com dados de teste
O HAPI FHIR é um servidor FHIR de código aberto conhecido. Usamos um servidor FHIR HAPI local no nosso codelab para conexão do app Android.
Configurar o servidor FHIR HAPI local
- Execute o seguinte comando em um terminal para acessar a imagem mais recente do FHIR da HAPI
docker pull hapiproject/hapi:latest
- Crie um contêiner FHIR da HAPI usando o Docker Desktop para executar a imagem de download anterior
hapiproject/hapi
ou executando 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. Aparecerá a interface da Web FHIR HAPI.
Preencher o servidor FHIR HAPI local com dados de teste
Para testar nosso aplicativo, precisaremos de alguns dados de teste no servidor. Usaremos dados sintéticos gerados pelo Synthea.
- Primeiro, precisamos fazer o download dos dados de amostra de synthea-samples. Faça o download e extraia o arquivo
synthea_sample_data_fhir_r4_sep2019.zip
. Os dados de amostra descompactados têm vários arquivos.json
, cada um sendo um pacote de transações para um paciente específico. - Vamos fazer o upload dos dados de testes de três pacientes para o servidor FHIR HAPI local. Execute o seguinte comando no diretório que contém os 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
- Verifique se os dados de teste estão disponíveis no servidor abrindo o URL
http://localhost:8080/fhir/Patient/
em um navegador. O textoHTTP 200 OK
e a seçãoResponse Body
da página com os dados dos pacientes serão exibidos em um pacote FHIR como o resultado da pesquisa com uma contagem detotal
.
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
Vamos começar importando o app inicial para o Android Studio.
Abra o Android Studio, selecione Import Project (Gradle, Eclipse ADT etc.) e escolha a pasta codelabs/engine/
no código-fonte que você baixou anteriormente.
Sincronizar o projeto com arquivos do Gradle
Para sua conveniência, as dependências da biblioteca FHIR Engine já foram adicionadas ao projeto. Isso permite integrar a biblioteca FHIR Engine ao seu aplicativo. Observe as seguintes linhas no final do arquivo app/build.gradle.kts
do projeto:
dependencies {
// ...
implementation("com.google.android.fhir:engine:0.1.0-beta05")
}
Para garantir que todas as dependências estejam disponíveis para o app, sincronize o projeto com os arquivos do Gradle neste momento.
Selecione Sync Project with Gradle Files () na barra de ferramentas do Android Studio. Execute 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 Run () na barra de ferramentas do Android Studio.
4. Criar instância do mecanismo FHIR
Para incorporar o FHIR Engine ao seu aplicativo Android, você precisará usar a biblioteca FHIR Engine e iniciar uma instância do FHIR Engine. As etapas descritas abaixo guiarão você ao longo do 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 for compatível.RECREATE_AT_OPEN
: determina a estratégia de erro do banco de dados. Nesse caso, ele recria o banco de dados caso ocorra um erro na abertura.baseUrl
emServerConfiguration
: é o URL base do servidor FHIR. O endereço IP fornecido10.0.2.2
é reservado especialmente para localhost, acessível pelo Android Emulator. Saiba mais.
- Na classe
FhirApplication
, adicione a linha a seguir para instanciar lentamente o mecanismo FHIR:
Isso garante que a instância do FhirEngine seja criada apenas quando for acessada pela primeira vez, não imediatamente quando o aplicativo for iniciado.private val fhirEngine: FhirEngine by lazy { FhirEngineProvider.getInstance(this) }
- Adicione o seguinte método de conveniência na classe
FhirApplication
para facilitar o acesso em todo o aplicativo:
Com esse método estático, é possível recuperar a instância do FHIR Engine de qualquer lugar no aplicativo 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 aula, você vai definir como o aplicativo busca o próximo recurso da lista para download:
Esta classe tem uma fila de tipos de recursos para download. Ele processa 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 } }
- Criar uma nova classe
AppFhirSyncWorker.kt
Essa classe define como o app será sincronizado com o servidor FHIR remoto usando um worker em segundo plano.
Aqui, definimos qual gerenciador de downloads, resolvedor de conflitos e instância do mecanismo FHIR serão usados 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) }
- No ViewModel,
PatientListViewModel.kt
, você vai configurar um mecanismo de sincronização única. Localize e adicione este código à funçãotriggerOneTimeSync()
:
Essa corrotina inicia uma sincronização única com o servidor FHIR usando o AppFhirSyncWorker definido anteriormente. Em seguida, a interface vai ser atualizada 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
:
Aqui, quando a sincronização terminar, uma mensagem de aviso será exibida notificando o usuário, e o app vai mostrar todos os pacientes invocando 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 servidor FHIR local serão transferidos por download e exibidos no aplicativo.
6. Modificar e fazer upload dos dados dos pacientes
Nesta seção, vamos orientar você no processo de modificação dos dados dos pacientes com base em critérios específicos e no upload dos dados atualizados para o servidor FHIR. Mais especificamente, vamos trocar as cidades dos endereços dos pacientes que residem em Wakefield
e Taunton
.
Etapa 1: configurar a lógica de modificação no PatientListViewModel
O código nesta seção foi 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 a cidade de endereço
Wakefield
.
Aqui, estamos usando 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 de endereço. O resultado será uma lista de pacientes de Wakefield. - Pesquisar pacientes em Taunton:da mesma forma, pesquise pacientes com a cidade de endereço
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 endereços de pacientes:confira cada paciente na lista
patientsFromWakefield
, mude a cidade paraTaunton
e atualize-os no mecanismo FHIR.
Da mesma forma, atualize cada paciente na listapatientsFromWakefield.forEach { it.resource.address.first().city = "Taunton" fhirEngine.update(it.resource) }
patientsFromTaunton
para que a cidade dele mude paraWakefield
.patientsFromTaunton.forEach { it.resource.address.first().city = "Wakefield" fhirEngine.update(it.resource) }
- Iniciar 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() }
}
significa 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. Você verá as cidades dos endereços do pacienteAaron697
eAbby752
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
está atualizada no servidor FHIR local.
Ao seguir estas etapas, você implementou com sucesso um mecanismo para modificar os dados dos pacientes e sincronizar as alterações com o servidor FHIR.
7. Procurar pacientes pelo nome
Pesquisar pacientes pelo nome pode fornecer uma maneira fácil de recuperar informações. Aqui, você será conduzido pelo processo de implementação desse recurso em seu aplicativo.
Etapa 1: atualizar a assinatura da função
Navegue até o arquivo PatientListViewModel.kt
e encontre a função chamada 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 atualização da IU, 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 nameQuery
não estiver vazio, a função de pesquisa vai filtrar os resultados para incluir apenas pacientes com a consulta especificada no nome.
Etapa 2: testar o novo recurso 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ê poderá inserir um nome (ou parte de um nome) para filtrar a lista de pacientes.
Com essas etapas concluídas, você aprimorou seu aplicativo, permitindo que os usuários pesquisem pacientes pelo nome com eficiência. 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 aplicativo:
- Usar a API Sync para sincronizar recursos FHIR com um servidor FHIR
- Usar a API Data Access para criar, ler, atualizar e excluir recursos FHIR locais
- Usar a API Search para pesquisar recursos FHIR locais
O que aprendemos
- Como configurar um servidor FHIR HAPI local
- Como fazer o upload de dados de teste para o servidor FHIR HAPI local
- Como criar um app Android usando a biblioteca FHIR Engine
- Como usar as APIs Sync, Data Access e Search na biblioteca FHIR Engine
Próximas etapas
- Confira 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