Ciclo de vida no Jetpack Compose   Parte do Android Jetpack.

Os componentes com reconhecimento de ciclo de vida executam ações em resposta a uma mudança no status do ciclo de vida da atividade do host. O androidx.lifecycle.compose artefato fornece APIs dedicadas que limpam automaticamente os recursos quando eles saem da tela ou quando o aplicativo entra em segundo plano.

As principais APIs incluem:

Essas integrações fornecem hooks convenientes para gerenciar ciclos de vida na hierarquia do Compose. Este documento descreve como elas podem ser usadas no seu app.

Coletar o estado do ciclo de vida com fluxos

O ciclo de vida expõe uma propriedade currentStateFlow, que fornece o Lifecycle.State atual como um StateFlow do Kotlin. Você pode coletar esse Flow como State. Isso permite que o app leia mudanças no ciclo de vida durante a composição.

val lifecycleOwner = LocalLifecycleOwner.current
val stateFlow = lifecycleOwner.lifecycle.currentStateFlow

val currentLifecycleState by stateFlow.collectAsState()

O exemplo anterior pode ser acessado usando o módulo lifecycle-common. O método currentStateAsState() está disponível no módulo lifecycle-runtime-compose, que permite ler o estado atual do ciclo de vida com uma única linha. O exemplo abaixo demonstra isso:

val lifecycleOwner = LocalLifecycleOwner.current
val currentLifecycleState = lifecycleOwner.lifecycle.currentStateAsState()

Executar código em eventos de ciclo de vida

Em vez de criar uma classe separada que implementa DefaultLifecycleObserver e adicioná-la manualmente ao ciclo de vida, você pode declarar a lógica do ciclo de vida inline usando efeitos específicos. LifecycleEffects permite executar um bloco quando um Lifecycle.Event específico ocorre diretamente na composição.

LifecycleEventEffect

Use LifecycleEventEffect para executar um bloco de código quando um evento específico ocorre. Isso é melhor para eventos únicos, como registro ou análise, em que nem o sucesso nem um resultado imediato são necessários.

@Composable
fun AnalyticsTracker(screenName: String) {
    // Log an event when the app receives ON_RESUME (e.g. comes to foreground)
    LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
        Analytics.logView(screenName)
    }
}

LifecycleStartEffect

Para operações de início/parada pareadas que precisam ser executadas enquanto o app está iniciado (visível) e limpas quando o app é interrompido (em segundo plano), use LifecycleStartEffect.

Semelhante a outros efeitos do Compose (como LaunchedEffect), LifecycleStartEffect aceita chaves. Quando a chave muda, ela aciona o bloco para ser executado de novo.

Quando um evento Lifecycle.Event.ON_STOP ocorre ou o efeito sai da composição, ele executa o bloco onStopOrDispose para limpar qualquer trabalho que fez parte do bloco inicial.

@Composable
fun LocationMonitor(locationManager: LocationManager) {
    // Starts monitoring when ON_START is dispatched
    // Stops monitoring when ON_STOP is dispatched
    //   (or the composable leaves the screen)
    LifecycleStartEffect(locationManager) {
        val listener = LocationListener { location ->
            /* update UI */
        }
        locationManager.requestLocationUpdates(listener)
        // The cleanup block automatically runs on ON_STOP or on disposal
        onStopOrDispose {
            locationManager.removeUpdates(listener)
        }
    }
}

Para informações sobre outros tipos de efeitos colaterais, consulte Efeitos colaterais no Compose.

LifecycleResumeEffect

O LifecycleResumeEffect funciona da mesma forma que o LifecycleStartEffect, mas está vinculado ao evento Lifecycle.Event.ON_RESUME. Ele também fornece um bloco onPauseOrDispose, que executa a limpeza quando ON_PAUSE é enviado ou o elemento combinável sai da tela.

Essa API é útil para recursos que precisam estar ativos apenas quando o usuário está interagindo com o app, por exemplo, câmeras ou animações.

@Composable
fun CameraPreview(cameraController: CameraController) {
    LifecycleResumeEffect(cameraController) {
        cameraController.startPreview()

        onPauseOrDispose {
            cameraController.stopPreview()
        }
    }
}

Acessar o LifecycleOwner

No Compose, o LifecycleOwner está implicitamente disponível no CompositionLocal chamado LocalLifecycleOwner. Por padrão, o host raiz da hierarquia de composição fornece esse proprietário.

val lifecycleOwner = LocalLifecycleOwner.current

Para muitos apps, inspecionar esse proprietário padrão ou transmiti-lo a efeitos com reconhecimento de ciclo de vida é suficiente. No entanto, para navegação personalizada ou layouts complexos, talvez seja necessário criar seu próprio LifecycleOwner para definir o escopo dos estados do ciclo de vida para seções específicas da interface. Por exemplo, as bibliotecas de navegação (como a Navigation 3) fazem isso automaticamente para dar a cada tela individual o próprio ciclo de vida.

Criar um LifecycleOwner personalizado

A API rememberLifecycleOwner() permite criar e lembrar um personalizadoLifecycleOwner. Isso é especialmente útil para componentes como um HorizontalPager, em que você quer que apenas a página visível e estabelecida seja RESUMED, definindo um maxState de STARTED para as páginas adjacentes fora da tela.

val pagerState = rememberPagerState(pageCount = { 10 })

HorizontalPager(state = pagerState) { pageNum ->
    val pageLifecycleOwner = rememberLifecycleOwner(
        maxState = if (pagerState.settledPage == pageNum) {
            Lifecycle.State.RESUMED
        } else {
            Lifecycle.State.STARTED
        }
    )

    CompositionLocalProvider(LocalLifecycleOwner provides pageLifecycleOwner) {
        // Your pages here. Their lifecycle-aware components respect the
        // custom maxState defined above.
    }
}

Para mais informações sobre CompositionLocal, consulte Dados com escopo local no CompositionLocal.

Práticas recomendadas para componentes com reconhecimento de ciclo de vida

  • Mantenha seus controladores de interface o mais simples possível. Eles não podem tentar adquirir os próprios dados. Em vez disso, use um ViewModel para fazer isso, e observe um StateFlow objeto para refletir as mudanças na interface.
  • Tente escrever interfaces baseadas em dados em que a responsabilidade do controlador é atualizar a interface à medida que os dados são modificados ou notificar as ações do usuário de volta para o ViewModel.
  • Inclua sua lógica de dados na ViewModel classe. ViewModel servirá como o conector entre o controlador de IU e o restante do app. Entretanto, tenha cuidado, porque não é responsabilidade do ViewModel buscar dados (por exemplo, de uma rede). Em vez disso, ViewModel precisa chamar o componente adequado para buscar os dados e, em seguida, fornecer o resultado para o controlador de interface.
  • Use corrotinas de Kotlin para gerenciar tarefas de longa duração e outras operações que podem ser executadas de forma assíncrona.
  • Mantenha a lógica de início/parada dentro do elemento combinável que realmente precisa dela. Dessa forma, a lógica é removida automaticamente se esse elemento da interface específico for removido da tela (por exemplo, dentro de um gráfico de navegação ou quando a visibilidade é condicional).
  • Use collectAsStateWithLifecycle para dados. Não inicie ou interrompa manualmente a coleta de Flow com base em eventos de ciclo de vida. Em vez disso, use collectAsStateWithLifecycle para converter streams em estado de interface de maneira eficiente. Isso economiza bateria e recursos, porque os Flows são pausados quando o app está em segundo plano.

Para mais informações sobre Flows, consulte Outros tipos de estado compatíveis.

Casos de uso para componentes com reconhecimento de ciclo de vida

Componentes com reconhecimento de ciclo de vida podem facilitar muito o gerenciamento de ciclos de vida em diversos casos. Vejas alguns exemplos:

  • Alternar entre atualizações de localização aproximada ou detalhada. Use LifecycleStartEffect para ativar atualizações de localização detalhadas enquanto o app estiver visível (ON_START) e limpe automaticamente o listener ou mude para atualizações aproximadas quando o app estiver em segundo plano (ON_STOP).
  • Parar e iniciar o armazenamento de vídeos em buffer. Use LifecycleResumeEffect para adiar a reprodução real do vídeo até que o app esteja totalmente em primeiro plano e interativo (ON_RESUME) e para garantir que a reprodução seja pausada e libere recursos quando o app estiver em segundo plano (ON_PAUSE).
  • Iniciar e interromper o streaming de rede. Use collectAsStateWithLifecycle para observar streams contínuos de dados (como um fluxo do Kotlin de um soquete de rede). Isso oferece atualização em tempo real enquanto um app está em primeiro plano e cancela automaticamente a coleta quando o app entra em segundo plano.
  • Pausar e retomar tarefas pesadas. Use LifecycleResumeEffect para pausar atualizações visuais pesadas quando o app estiver em segundo plano e retomá-las depois que o app estiver em primeiro plano.

Como processar eventos ON_STOP com segurança

O Compose foi projetado para processar eventos ON_STOP com segurança.

  • O estado é seguro:é possível atualizar MutableState (por exemplo, com uiState.value = ...) a qualquer momento, mesmo quando o app está em segundo plano. O Compose aguarda até que o app esteja visível para renderizar as mudanças.
  • Limpeza automática:com efeitos como LifecycleStartEffect, o bloco de limpeza (onStopOrDispose) é executado exatamente quando o ciclo de vida muda para STOPPED. Isso evita que você mantenha recursos pesados (como câmera ou localização) enquanto o app está em segundo plano.

Para mais informações sobre MutableState, consulte Estado e Jetpack Compose.

Outros recursos

Para saber mais sobre como lidar com ciclos de vida com componentes que os reconhecem, consulte os seguintes recursos.

Conteúdo de visualizações