Introdução aos fluxos

A versão Kotlin das APIs Home usa fluxos, um recurso da linguagem Kotlin que oferece recursos avançados para lidar com fluxos de dados assíncronos, incluindo transformação, filtragem, mapeamento, conversão de e para coleções e assim por diante.

As corrotinas estão estreitamente associadas aos fluxos e oferecem uma abstração elegante para a gravação de código assíncrono e liberam o desenvolvedor de ter que gravar rotinas de callback explicitamente. Os fluxos funcionam em conjunto com as corrotinas, servindo como uma maneira de extrair dados de corrotinas de forma assíncrona, sem precisar aguardar a conclusão de uma função ou linha de execução.

Os dados são extraídos de um fluxo pelo consumidor em um processo chamado coleta. Os fluxos do Kotlin têm uma função collect() que pode ser usada para esse fim. O que acontece em um fluxo durante a coleta depende do tipo de fluxo.

Os fluxos do Kotlin (Flow<T>) são frios por padrão, o que significa que o código do builder de fluxos produz dados somente quando collect() é chamado. Um fluxo quente, por outro lado, produz dados imediatamente, armazenando-os em buffer na memória como uma fila sempre que os dados são consumidos. Como ele mantém dados na memória, um fluxo quente é considerado como stateful.

Os fluxos podem ser convertidos de frio para quente usando o operador shareIn. Consulte Como converter fluxos frios em quentes usando shareIn. Você também pode usar SharedFlow ou StateFlow para transformar um fluxo frio em um quente.

Como o app de exemplo usa fluxos

O app de exemplo usa modelos de visualização no Jetpack Compose conectado aos fluxos nas APIs Home. Muitos dos elementos da interface de exemplo do app são orientados por estado, mas podem ser usados para interação. O app de exemplo também combina o estado dos dispositivos com um estado "otimista" na interface para uma experiência do usuário em tempo real. O termo otimista significa que o app presume que uma determinada ação foi concluída e atualiza imediatamente a interface para refletir o resultado esperado sem esperar a confirmação. Se a ação falhar, a interface será atualizada para refletir o estado real.

No app de exemplo, os fluxos são criados para cada camada do modelo de visualização (estruturas, ambientes, dispositivos). Por exemplo, ele faz isso para estruturas com a seguinte chamada em GlobalViewModel.kt:

  fun getStructuresState(): StateFlow<List<StructureModel>?> =
    homeClient
      .structures()
      .map { structures -> structures.map { StructureModel(it.name, it) }.sortedBy { it.name } }
      .handleErrors()
      .flowOn(Dispatchers.IO)
      .stateIn(scope = viewModelScope, started = SharingStarted.WhileSubscribed(), null)

emitAll() coleta todos os valores do fluxo especificado e os emite para o coletor. O stateIn() compartilha o valor emitido mais recentemente de uma única instância em execução do fluxo upstream com vários assinantes downstream. Consulte a referência kotlinx.coroutines.flow para mais informações.

Jetpack Compose

Para armazenar objetos de fluxo na memória local e evitar que eles sejam encerrados, use a API remember do Kotlin.

No Jetpack Compose, se você usar isso com collectAsStateWithLifecycle(), o Jetpack vai gerenciar automaticamente a inscrição e a remoção de inscrição de fluxos com base em se a interface do aplicativo que mostra esse estado está realmente em primeiro plano ou não.

Uma chamada simples no app de exemplo faz isso. Usando a função getStructuresState() mostrada anteriormente:

val structuresList by
    remember(globalViewModel) { globalViewModel.getStructuresState() }.collectAsStateWithLifecycle()

Agora, quando qualquer estado da estrutura muda (como o name), a função combinável que o usa reflete esse estado atualizado automaticamente. No app de exemplo, essa é a função HomeActivityContent().

Recursos

Para mais informações sobre Kotlin, fluxos, corrotinas e Jetpack Compose, consulte os seguintes recursos: