As corrotinas do Kotlin fornecem uma API que permite escrever código
assíncrono. Com as corrotinas do Kotlin, é possível definir um CoroutineScope, que
ajuda a gerenciar quando as corrotinas precisam ser executadas. Cada operação assíncrona
é executada em um escopo específico.
Os componentes com reconhecimento de ciclo de vida oferecem suporte de primeira classe para corrotinas em escopos lógicos no app. Este documento explica como usar corrotinas de maneira eficaz com componentes com reconhecimento de ciclo de vida.
Adicionar dependências
Os escopos de corrotina integrados descritos neste tópico estão contidos na API Lifecycle. Adicione as dependências adequadas ao usar esses escopos.
- Para utilitários do ViewModel no Compose, use
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"). - Para utilitários do Lifecycle no Compose, use
implementation("androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version").
Escopos de corrotina com reconhecimento de ciclo de vida
O Compose e as bibliotecas de ciclo de vida fornecem os seguintes escopos integrados que podem ser usados no seu app.
ViewModelScope
Um ViewModelScope é definido para cada ViewModel no app. Qualquer
corrotina iniciada nesse escopo será cancelada automaticamente se o ViewModel for
apagado. As corrotinas são úteis quando você tem um trabalho que precisa ser feito
somente se o ViewModel estiver ativo. Por exemplo, se você estiver computando alguns dados
de um layout, será necessário definir o escopo do trabalho como ViewModel. Dessa forma, o trabalho será cancelado automaticamente para evitar o consumo
de recursos caso o ViewModel seja apagado.
É possível acessar o CoroutineScope de um ViewModel pela propriedade viewModelScope do ViewModel, conforme mostrado no exemplo a seguir:
class MyViewModel: ViewModel() {
init {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
}
}
}
Para casos de uso mais avançados, transmita um CoroutineScope personalizado diretamente
para o construtor do ViewModel para substituir o viewModelScope padrão. Essa
abordagem oferece mais controle e flexibilidade, principalmente para:
Teste: permite injetar um
TestScope, facilitando o controle do tempo e a verificação do comportamento da corrotina em testes de unidade.Configuração personalizada: é possível configurar o escopo com um
CoroutineDispatcherespecífico (comoDispatchers.Defaultpara computação pesada) ou umCoroutineExceptionHandlerpersonalizado antes mesmo que o ViewModel comece o trabalho.
Escopos vinculados à composição
Efeitos colaterais, como animações, chamadas de rede ou timers, precisam ser limitados ao ciclo de vida do elemento que pode ser composto. Dessa forma, quando um elemento combinável sai da tela (sai da composição), todas as corrotinas em execução são canceladas automaticamente para evitar vazamentos de memória.
O Compose oferece a API LaunchedEffect para processar o escopo da composição de forma
declarativa.
LaunchedEffect cria um CoroutineScope que permite executar funções de
suspensão. O escopo está vinculado ao ciclo de vida da composição do elemento combinável, não
ao ciclo de vida da atividade host.
- Entrada: a corrotina é iniciada quando o elemento combinável entra na composição.
- Saída: a corrotina é cancelada quando o elemento combinável sai da composição.
- Reinicialização: se alguma chave transmitida para
LaunchedEffectmudar, a corrotina atual será cancelada e uma nova será iniciada.
O exemplo a seguir demonstra como usar LaunchedEffect para criar uma
animação pulsante. A corrotina está vinculada à presença do elemento combinável na
composição e reage às mudanças de configuração:
// Allow the pulse rate to be configured, so it can be sped up if the user is running // out of time var pulseRateMs by remember { mutableLongStateOf(3000L) } val alpha = remember { Animatable(1f) } LaunchedEffect(pulseRateMs) { // Restart the effect when the pulse rate changes while (isActive) { delay(pulseRateMs) // Pulse the alpha every pulseRateMs to alert the user alpha.animateTo(0f) alpha.animateTo(1f) } }
Para mais informações sobre LaunchedEffect, consulte Efeitos colaterais no Compose.
Coleta de fluxo com reconhecimento de ciclo de vida
Para coletar fluxos com segurança no Jetpack Compose, use a
API collectAsStateWithLifecycle. Essa função única converte um Flow
em um objeto State do Compose e gerencia automaticamente a inscrição
do ciclo de vida para você. Por padrão, a coleta começa quando o ciclo de vida é
STARTED e para quando o ciclo de vida é STOPPED. Para modificar esse comportamento
padrão, transmita o parâmetro minActiveState com o método de ciclo de vida
que você quer, como Lifecycle.State.RESUMED.
O exemplo abaixo demonstra como coletar o StateFlow de um ViewModel em um
combinável:
@Composable private fun ConversationScreen( conversationViewModel: ConversationViewModel = viewModel() ) { val messages by conversationViewModel.messages.collectAsStateWithLifecycle() ConversationScreen( messages = messages, onSendMessage = { message: Message -> conversationViewModel.sendMessage(message) } ) } @Composable private fun ConversationScreen( messages: List<Message>, onSendMessage: (Message) -> Unit ) { MessagesList(messages, onSendMessage) /* ... */ }
Coleta paralela de vários fluxos
No Compose, é possível coletar vários fluxos em paralelo declarando várias
variáveis de estado. Como collectAsStateWithLifecycle gerencia o próprio
escopo, a coleta paralela é processada automaticamente:
@Composable
fun DashboardScreen(viewModel: DashboardViewModel = viewModel()) {
// Both flows are collected safely in parallel and will emit updates when either changes, the composables will recompose
val userData by viewModel.userFlow.collectAsStateWithLifecycle()
val feedData by viewModel.feedFlow.collectAsStateWithLifecycle()
// ...
}
Calcular valores de forma assíncrona usando fluxos
Quando você precisar calcular valores de forma assíncrona, use StateFlow com o
operador stateIn.
O snippet a seguir usa um Flow padrão convertido em um StateFlow. O parâmetro
WhileSubscribed(5000) mantém a inscrição ativa por cinco
segundos após o desaparecimento da interface para processar mudanças de configuração.
val uiState: StateFlow<Result> = flow {
emit(repository.fetchData())
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = Result.Loading
)
Use collectAsStateWithLifecycle para converter os valores coletados em
State do Compose, para que a IU possa ser atualizada de forma reativa sempre que os dados mudarem.
Para mais informações sobre o estado, consulte Estado e Jetpack Compose.
Outros recursos
Visualiza conteúdo
Amostras
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Como gerenciar ciclos de vida com componentes que os reconhecem
- Carregar e exibir dados paginados