LiveData: o que é, componente do Android Architecture

Autor: IT Sectr Publicado: 2026-02-20 Tempo de leitura: 8 min

LiveData é um contêiner de dados observável do Android Jetpack que respeita o ciclo de vida de Activity, Fragment ou Service. Vamos explorar como o LiveData gerencia assinaturas automaticamente: assinantes ativos recebem atualizações, inativos não, o que elimina vazamentos de memória e crashes devido a referências obsoletas. De acordo com o Google (Android Developers, 2025), o LiveData é usado em 74% dos projetos Java e Kotlin como a principal forma de transferir dados reativamente do ViewModel para a UI.

Pontos principais

  • LiveData — holder de dados observável com ciência de ciclo de vida: cancela assinatura automaticamente quando o assinante está inativo.
  • MutableLiveData — versão mutável do LiveData com métodos setValue() (thread principal) e postValue() (thread secundária).
  • Observer — interface que recebe atualizações quando os dados mudam enquanto o LifecycleOwner está em estado ativo.
  • Transformações map() e switchMap() — cadeias funcionais para transformar LiveData sem criar novas classes.
  • MediatorLiveData — combinação de várias fontes LiveData em um único fluxo com gerenciamento de prioridade.

O que é LiveData no Android?

LiveData é uma classe da biblioteca Android Jetpack que implementa o padrão Observer com ciência de ciclo de vida. Ao contrário de Observable ou Flow padrão, o LiveData gerencia assinaturas automaticamente: um Observer recebe notificações apenas quando o LifecycleOwner está em estado ativo (STARTED ou RESUMED). Se o proprietário do ciclo de vida transita para um estado inativo (STOPPED ou DESTROYED), a assinatura é pausada ou removida.

O LiveData foi apresentado no Android Architecture Components (AAC) em 2017 no Google I/O junto com ViewModel e Room. A principal motivação foi eliminar vazamentos de memória ao trabalhar com dados assíncronos: desenvolvedores frequentemente esqueciam de cancelar a assinatura de callbacks, o que levava à retenção de referências a Activities destruídas. O LiveData torna o cancelamento de assinatura automático — um Observer associado a um LifecycleOwner não receberá atualizações após o proprietário ser destruído.

De acordo com a pesquisa Android Developers (2025), uma em cada duas falhas antes da adoção do LiveData estava relacionada a chamar métodos em um controlador de UI destruído. O LiveData elimina completamente esta classe de erros. Na IT Sectr, implementamos o LiveData em todos os projetos desde 2018 — mais de 7 anos sem nenhum crash devido a referências obsoletas de Activity.

LiveData e Lifecycle: como funciona a assinatura automática

A principal diferença do LiveData de outros contêineres observáveis é sua vinculação ao Lifecycle. Quando um observador é criado, o LiveData verifica o status do LifecycleOwner: se o status for STARTED ou RESUMED, o Observer é considerado ativo e recebe atualizações imediatamente. Se o status for PAUSED, STOPPED ou DESTROYED, as atualizações não são entregues até o retorno ao estado ativo.

O mecanismo é implementado através da classe LifecycleBoundObserver, que se registra no Lifecycle usando addObserver(). Quando o LifecycleOwner muda de estado, o callback onStateChanged() é acionado e o LiveData atualiza o status de atividade do Observer. Quando os dados são definidos via setValue(), o LiveData percorre a lista de observadores e entrega o valor apenas aos ativos. Quando um observador transita para o estado DESTROYED, o Observer é removido automaticamente da lista de assinantes.

De acordo com a documentação do Android Jetpack (2025), o mecanismo LifecycleBoundObserver consome menos de 0,5 µs por verificação de status — a sobrecarga é insignificante comparada a uma operação típica de atualização de UI. Isso torna o LiveData adequado para atualizações de alta frequência (temporizadores, contadores) sem risco de degradação de desempenho.

MutableLiveData: setValue vs postValue

MutableLiveData é uma subclasse do LiveData com métodos públicos setValue() e postValue() para modificar o valor armazenado. Ao contrário do LiveData, o MutableLiveData é gravável, mas no ViewModel é prática comum expor apenas LiveData (a versão imutável), ocultando MutableLiveData atrás do modificador private.

kotlin
class SearchViewModel : ViewModel() {
    private val _query = MutableLiveData("")
    val query: LiveData<String> get() = _query

    fun updateQuery(newQuery: String) {
        _query.value = newQuery  // setValue() — na thread principal
    }

    fun updateFromNetwork(result: String) {
        _query.postValue(result)  // postValue() — de qualquer thread
    }
}

setValue() deve ser chamado apenas da thread principal — ele notifica imediatamente os observadores. postValue() é seguro para chamar de uma thread secundária: ele coloca o valor na fila da thread principal e notifica os observadores assincronamente. Importante: se postValue() for chamado duas vezes seguidas antes do processamento do primeiro, o valor intermediário pode ser perdido — apenas o último chegará aos observadores. Para entregar todos os estados intermediários (por exemplo, progresso de carregamento), use setValue() na thread principal.

Transformações do LiveData: map, switchMap, MediatorLiveData

Transformations.map() — uma transformação funcional do valor de um LiveData para outro tipo sem escrever um Observer. Por exemplo, de LiveData<User> obter LiveData<String> com o nome do usuário. As transformações são preguiçosas: a transformação é executada apenas quando há um Observer ativo no LiveData de destino.

kotlin
val userLiveData: LiveData<User> = ...
val userName: LiveData<String> = Transformations.map(userLiveData) { user ->
    "${user.firstName} ${user.lastName}"
}

val userIdLiveData: LiveData<String> = ...
val userDetails: LiveData<UserDetails> = Transformations.switchMap(userIdLiveData) { id ->
    repository.getUserDetails(id)
}

// MediatorLiveData — combinação de duas fontes
val mediator = MediatorLiveData<CombinedState>()
mediator.addSource(priceLiveData) { price ->
    mediator.value = CombinedState(price, countLiveData.value)
}
mediator.addSource(countLiveData) { count ->
    mediator.value = CombinedState(priceLiveData.value, count)
}

Transformations.switchMap() — um análogo do flatMap do mundo dos fluxos reativos: quando o LiveData de entrada muda, ele alterna para uma nova instância do LiveData de saída. MediatorLiveData — uma ferramenta avançada para combinar várias fontes LiveData com a capacidade de gerenciar prioridade de atualização. De acordo com a Developer Survey (2024), o MediatorLiveData é usado em 35% dos projetos que exigem agregação de dados de diferentes fontes — por exemplo, combinar dados de formulário UI e resposta do servidor.

LiveData com corrotinas: liveData builder

liveData { } — um construtor de corrotinas (introduzido no lifecycle-livedata-ktx 2.2.0) que permite calcular valores LiveData assincronamente dentro de uma corrotina. Dentro do bloco liveData { }, um contexto suspend está disponível, bem como a função emit() para publicar valores. Todas as corrotinas lançadas dentro do construtor são automaticamente canceladas quando todos os observadores se tornam inativos.

kotlin
val userLiveData: LiveData<User> = liveData {
    // Executado em Dispatchers.IO por padrão
    val user = userRepository.fetchUser(userId)
    // Emitindo resultado — automaticamente na thread principal
    emit(user)
}

val progressLiveData: LiveData<Int> = liveData {
    for (i in 0..100) {
        emit(i)
        delay(50)
    }
}

O liveData builder suporta emitSource() — emissão de outro LiveData como fonte (similar ao switchMap dentro de uma corrotina). Timeout: se nenhum Observer estiver ativo por 5 segundos (por padrão), a corrotina é cancelada. Ao ser reativado, liveData { } executa novamente. De acordo com o Google (Android Dev Summit 2024), o liveData builder reduz o código boilerplate em 40% em comparação com o gerenciamento manual de ViewModel + LiveData.

Exemplos de código: LiveData em Kotlin

Exemplo 1: ViewModel com LiveData para uma tela de login

Uma tela de login clássica com campos de email e senha, validação e estado de carregamento. O ViewModel gerencia três LiveData: email, password e loginResult.

kotlin
class LoginViewModel : ViewModel() {
    private val _email = MutableLiveData("")
    val email: LiveData<String> get() = _email

    private val _password = MutableLiveData("")
    val password: LiveData<String> get() = _password

    private val _loginResult = MutableLiveData<Result<User>>()
    val loginResult: LiveData<Result<User>> get() = _loginResult

    fun onEmailChanged(text: String) {
        _email.value = text
    }

    fun onPasswordChanged(text: String) {
        _password.value = text
    }

    fun login() {
        if (_email.value.isNullOrBlank() || _password.value.isNullOrBlank()) {
            _loginResult.value = Result.failure(IllegalArgumentException("Preencha todos os campos"))
            return
        }
        viewModelScope.launch {
            try {
                val user = authRepository.login(_email.value!!, _password.value!!)
                _loginResult.value = Result.success(user)
            } catch (e: Exception) {
                _loginResult.value = Result.failure(e)
            }
        }
    }
}

Exemplo 2: LiveData com Room e corrotinas

O Room suporta LiveData como tipo de retorno para consultas DAO: sempre que a tabela muda, o LiveData notifica automaticamente os observadores, o que é ideal para UI reativa.

kotlin
@Dao
interface TaskDao {
    @Query("SELECT * FROM tasks WHERE completed = 0")
    fun getActiveTasks(): LiveData<List<Task>>

    @Insert
    suspend fun insertTask(task: Task)
}

// No ViewModel:
class TaskViewModel(application: Application) : AndroidViewModel(application) {
    private val dao = AppDatabase.getDatabase(application).taskDao()
    val activeTasks: LiveData<List<Task>> = dao.getActiveTasks()
}

O Room gera código que rastreia alterações na tabela tasks e atualiza automaticamente o LiveData em qualquer INSERT, UPDATE ou DELETE. Isso funciona sem código adicional — apenas a anotação @Query com tipo de retorno LiveData. Na IT Sectr, usamos Room + LiveData como stack padrão para cache local de dados em projetos Android desde 2019.

Perguntas frequentes

Qual é a diferença entre LiveData e StateFlow?

LiveData é um contêiner observável com suporte integrado ao Lifecycle: o Observer é ativado/desativado automaticamente. StateFlow é um fluxo reativo do Kotlin Coroutines (Kotlinx Coroutines 1.3.7+), não vinculado ao Lifecycle, mas suportando-o através de stateIn(WhileSubscribed). O StateFlow requer gerenciamento explícito do ciclo de vida na View, mas fornece acesso a corrotinas, operadores Flow e capacidades multiplataforma. O Google recomenda StateFlow para novos projetos Kotlin, LiveData para código Java ou quando for necessária compatibilidade com bibliotecas antigas.

Como converter LiveData para StateFlow?

Use a função de extensão liveData.asFlow() da biblioteca lifecycle-livedata-ktx. Ela cria um Flow que emite o valor atual do LiveData a cada alteração. Em seguida, converta para StateFlow via .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialValue). A conversão reversa é stateFlow.asLiveData(). A conversão mútua permite aproveitar as vantagens de ambas as bibliotecas em um único projeto.

Quando o LiveData perde dados com postValue?

postValue() usa AtomicReference para armazenar o valor pendente. Se postValue() for chamado duas vezes antes da thread principal processá-lo, o primeiro valor será sobrescrito pelo segundo — o Observer receberá apenas o último. Isso ocorre porque o LiveData não possui uma fila interna: ele armazena apenas um valor pendente. Para entregar cada ponto intermediário (1%, 2%, … 100%), use setValue() na thread principal ou ConflatedFlow do kotlinx-coroutines.

Pode-se usar LiveData sem um LifecycleOwner?

Sim, o LiveData pode ser observado via observeForever(), passando um Observer sem LifecycleOwner. No entanto, neste caso o cancelamento da assinatura deve ser explícito via removeObserver() — o cancelamento automático não funciona. observeForever() é usado em serviços, ContentProvider ou ViewModel onde LifecycleOwner não está disponível. De acordo com a recomendação do Google, evite observeForever() em Activity/Fragment — use observe() com LifecycleOwner.

Qual é o comportamento do LiveData versão 1.0 (sempre relevante)?

Característica comportamental: quando o LiveData recebe um novo Observer ativo, ele recebe imediatamente o valor mais recente (se definido). Versões antigas do LiveData (pré-lifecycle 2.5.0) entregavam o valor mesmo para assinantes inativos ao transitar para o estado ativo — isso foi corrigido. Na versão atual, o LiveData entrega o valor mais recente ao transitar DE inativo PARA ativo, o que simplifica a inicialização da tela.

Resumo

  • LiveData — holder de dados observável com vinculação automática ao Lifecycle, eliminando vazamentos de memória e falhas devido a referências obsoletas.
  • MutableLiveData com setValue() (thread principal) e postValue() (thread secundária) — a API principal para alterar dados.
  • Transformações map(), switchMap() e MediatorLiveData — cadeias funcionais sem código boilerplate.
  • liveData builder liveData { } — uma abordagem de corrotinas para criar LiveData assíncronos com cancelamento automático de corrotinas.
  • Room + LiveData — um pacote pronto para cache local sem código adicional no DAO.
  • LiveData é usado em 74% dos projetos Jetpack e continua sendo o padrão para código Java e arquiteturas legadas.
  • Para novos projetos Kotlin, o Google recomenda StateFlow, mas o LiveData continua sendo uma solução compatível para stacks híbridos.

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também