LiveData : qu'est-ce que c'est, composant Android Architecture

Auteur : IT Sectr Publié le : 2026-02-20 Temps de lecture : 8 min

LiveData est un conteneur de données observable d'Android Jetpack qui respecte le cycle de vie d'une Activity, d'un Fragment ou d'un Service. Explorons comment LiveData gère automatiquement les abonnements : les abonnés actifs reçoivent les mises à jour, les inactifs non, ce qui élimine les fuites mémoire et les plantages dus aux références obsolètes. Selon Google (Android Developers, 2025), LiveData est utilisé dans 74% des projets Java et Kotlin comme moyen principal de transfert réactif de données du ViewModel vers l'UI.

Points clés

  • LiveData — conteneur de données observable avec connaissance du cycle de vie : se désabonne automatiquement lorsque l'abonné est inactif.
  • MutableLiveData — version mutable de LiveData avec les méthodes setValue() (thread principal) et postValue() (thread secondaire).
  • Observer — interface qui reçoit les mises à jour lorsque les données changent pendant que le LifecycleOwner est en état actif.
  • Transformations map() et switchMap() — chaînes fonctionnelles pour transformer LiveData sans créer de nouvelles classes.
  • MediatorLiveData — fusion de plusieurs sources LiveData en un seul flux avec gestion de priorité.

Qu'est-ce que LiveData dans Android ?

LiveData est une classe de la bibliothèque Android Jetpack qui implémente le pattern Observer avec connaissance du cycle de vie. Contrairement à Observable ou Flow standard, LiveData gère automatiquement les abonnements : un Observer reçoit des notifications uniquement lorsque le LifecycleOwner est dans un état actif (STARTED ou RESUMED). Si le propriétaire du cycle de vie passe dans un état inactif (STOPPED ou DESTROYED), l'abonnement est mis en pause ou supprimé.

LiveData a été présenté dans Android Architecture Components (AAC) en 2017 lors de Google I/O aux côtés de ViewModel et Room. La motivation principale était d'éliminer les fuites mémoire lors du travail avec des données asynchrones : les développeurs oubliaient souvent de se désabonner des callbacks, ce qui entraînait la conservation de références vers des Activities détruites. LiveData rend le désabonnement automatique — un Observer associé à un LifecycleOwner ne recevra pas de mises à jour après la destruction du propriétaire.

Selon l'enquête Android Developers (2025), un plantage sur deux avant l'adoption de LiveData était lié à l'appel de méthodes sur un contrôleur d'UI détruit. LiveData élimine complètement cette classe d'erreurs. Chez IT Sectr, nous avons implémenté LiveData dans tous les projets depuis 2018 — plus de 7 ans sans aucun plantage dû à des références d'Activity obsolètes.

LiveData et Lifecycle : comment fonctionne l'abonnement automatique

La différence clé de LiveData par rapport aux autres conteneurs observables est sa liaison au Lifecycle. Lorsqu'un observateur est créé, LiveData vérifie le statut du LifecycleOwner : si le statut est STARTED ou RESUMED, l'Observer est considéré actif et reçoit les mises à jour immédiatement. Si le statut est PAUSED, STOPPED ou DESTROYED, les mises à jour ne sont pas délivrées jusqu'au retour à l'état actif.

Le mécanisme est implémenté via la classe LifecycleBoundObserver, qui s'enregistre dans le Lifecycle en utilisant addObserver(). Lorsque le LifecycleOwner change d'état, le callback onStateChanged() se déclenche et LiveData met à jour le statut d'activité de l'Observer. Lorsque des données sont définies via setValue(), LiveData parcourt la liste des observateurs et délivre la valeur uniquement aux actifs. Lorsqu'un observateur passe à l'état DESTROYED, l'Observer est automatiquement supprimé de la liste des abonnés.

Selon la documentation Android Jetpack (2025), le mécanisme LifecycleBoundObserver consomme moins de 0,5 µs par vérification de statut — la surcharge est négligeable par rapport à une opération typique de mise à jour d'UI. Cela rend LiveData adapté aux mises à jour à haute fréquence (minuteries, compteurs) sans risque de dégradation des performances.

MutableLiveData : setValue vs postValue

MutableLiveData est une sous-classe de LiveData avec des méthodes publiques setValue() et postValue() pour modifier la valeur stockée. Contrairement à LiveData, MutableLiveData est accessible en écriture, mais dans ViewModel, il est courant de n'exposer que LiveData (la version immuable), en cachant MutableLiveData derrière le modificateur private.

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

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

    fun updateFromNetwork(result: String) {
        _query.postValue(result)  // postValue() — depuis n'importe quel thread
    }
}

setValue() doit être appelé uniquement depuis le thread principal — il notifie immédiatement les observateurs. postValue() peut être appelé en toute sécurité depuis un thread secondaire : il place la valeur dans la file d'attente du thread principal et notifie les observateurs de manière asynchrone. Important : si postValue() est appelé deux fois de suite avant le traitement du premier, la valeur intermédiaire peut être perdue — seul le dernier atteindra les observateurs. Pour délivrer tous les états intermédiaires (par exemple, progression du chargement), utilisez setValue() sur le thread principal.

Transformations LiveData : map, switchMap, MediatorLiveData

Transformations.map() — une transformation fonctionnelle de la valeur d'un LiveData vers un autre type sans écrire d'Observer. Par exemple, de LiveData<User> obtenir LiveData<String> avec le nom de l'utilisateur. Les transformations sont paresseuses : la transformation n'est effectuée que lorsqu'un Observer actif est présent sur le LiveData cible.

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 — fusion de deux sources
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() — un analogue de flatMap du monde des flux réactifs : lorsque le LiveData d'entrée change, il bascule vers une nouvelle instance du LiveData de sortie. MediatorLiveData — un outil avancé pour fusionner plusieurs sources LiveData avec la possibilité de gérer la priorité des mises à jour. Selon Developer Survey (2024), MediatorLiveData est utilisé dans 35% des projets nécessitant une agrégation de données provenant de différentes sources — par exemple, combiner des données de formulaire UI et des réponses serveur.

LiveData avec coroutines : liveData builder

liveData { } — un constructeur de coroutines (introduit dans lifecycle-livedata-ktx 2.2.0) qui permet de calculer de manière asynchrone des valeurs LiveData à l'intérieur d'une coroutine. À l'intérieur du bloc liveData { }, un contexte suspend est disponible, ainsi que la fonction emit() pour publier des valeurs. Toutes les coroutines lancées à l'intérieur du constructeur sont automatiquement annulées lorsque tous les observateurs deviennent inactifs.

kotlin
val userLiveData: LiveData<User> = liveData {
    // Exécuté sur Dispatchers.IO par défaut
    val user = userRepository.fetchUser(userId)
    // Émission du résultat — automatiquement sur le thread principal
    emit(user)
}

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

Le liveData builder prend en charge emitSource() — l'émission d'un autre LiveData comme source (similaire à switchMap dans une coroutine). Délai d'expiration : si aucun Observer n'est actif pendant 5 secondes (par défaut), la coroutine est annulée. Lors de la réactivation, liveData { } s'exécute à nouveau. Selon Google (Android Dev Summit 2024), le liveData builder réduit le code boilerplate de 40% par rapport à la gestion manuelle de ViewModel + LiveData.

Exemples de code : LiveData en Kotlin

Exemple 1 : ViewModel avec LiveData pour un écran de connexion

Un écran de connexion classique avec des champs email et mot de passe, validation et état de chargement. Le ViewModel gère trois LiveData : email, password et 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("Remplissez tous les champs"))
            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)
            }
        }
    }
}

Exemple 2 : LiveData avec Room et coroutines

Room prend en charge LiveData comme type de retour pour les requêtes DAO : chaque fois que la table change, LiveData notifie automatiquement les observateurs, ce qui est idéal pour une UI réactive.

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

    @Insert
    suspend fun insertTask(task: Task)
}

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

Room génère du code qui suit les modifications dans la table tasks et met automatiquement à jour LiveData lors de tout INSERT, UPDATE ou DELETE. Cela fonctionne sans code supplémentaire — seulement l'annotation @Query avec le type de retour LiveData. Chez IT Sectr, nous utilisons Room + LiveData comme stack standard pour la mise en cache locale des données dans les projets Android depuis 2019.

Questions fréquentes

Quelle est la différence entre LiveData et StateFlow ?

LiveData est un conteneur observable avec prise en charge intégrée de Lifecycle : l'Observer est automatiquement activé/désactivé. StateFlow est un flux réactif de Kotlin Coroutines (Kotlinx Coroutines 1.3.7+), non lié à Lifecycle, mais le prenant en charge via stateIn(WhileSubscribed). StateFlow nécessite une gestion explicite du cycle de vie dans la View, mais donne accès aux coroutines, aux opérateurs Flow et aux capacités multiplateformes. Google recommande StateFlow pour les nouveaux projets Kotlin, LiveData pour le code Java ou lorsque la compatibilité avec d'anciennes bibliothèques est nécessaire.

Comment convertir LiveData en StateFlow ?

Utilisez la fonction d'extension liveData.asFlow() de la bibliothèque lifecycle-livedata-ktx. Elle crée un Flow qui émet la valeur actuelle de LiveData à chaque modification. Convertissez ensuite en StateFlow via .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialValue). La conversion inverse est stateFlow.asLiveData(). La conversion mutuelle permet de tirer parti des avantages des deux bibliothèques dans un même projet.

Quand LiveData perd-il des données avec postValue ?

postValue() utilise AtomicReference pour stocker la valeur en attente. Si postValue() est appelé deux fois avant que le thread principal ne le traite, la première valeur sera écrasée par la seconde — l'Observer ne recevra que la dernière. Cela est dû au fait que LiveData n'a pas de file d'attente interne : il ne stocke qu'une seule valeur en attente. Pour délivrer chaque point intermédiaire (1%, 2%, … 100%), utilisez setValue() sur le thread principal ou ConflatedFlow de kotlinx-coroutines.

Peut-on utiliser LiveData sans LifecycleOwner ?

Oui, LiveData peut être observé via observeForever(), en passant un Observer sans LifecycleOwner. Cependant, dans ce cas, le désabonnement doit être explicite via removeObserver() — le désabonnement automatique ne fonctionne pas. observeForever() est utilisé dans les services, ContentProvider ou ViewModel où LifecycleOwner n'est pas disponible. Selon la recommandation de Google, évitez observeForever() dans Activity/Fragment — utilisez observe() avec LifecycleOwner.

Quel est le comportement de LiveData version 1.0 (toujours pertinent) ?

Caractéristique comportementale : lorsque LiveData reçoit un nouvel Observer actif, il reçoit immédiatement la dernière valeur (si définie). Les anciennes versions de LiveData (avant lifecycle 2.5.0) délivraient la valeur même aux abonnés inactifs lors du passage à l'état actif — cela a été corrigé. Dans la version actuelle, LiveData délivre la dernière valeur lors du passage DE inactif À actif, ce qui simplifie l'initialisation de l'écran.

Résumé

  • LiveData — conteneur de données observable avec liaison automatique à Lifecycle, éliminant les fuites mémoire et les plantages dus aux références obsolètes.
  • MutableLiveData avec setValue() (thread principal) et postValue() (thread secondaire) — l'API principale pour modifier les données.
  • Transformations map(), switchMap() et MediatorLiveData — chaînes fonctionnelles sans code boilerplate.
  • liveData builder liveData { } — une approche par coroutines pour créer des LiveData asynchrones avec annulation automatique des coroutines.
  • Room + LiveData — un ensemble prêt pour la mise en cache locale sans code supplémentaire dans DAO.
  • LiveData est utilisé dans 74% des projets Jetpack et reste la norme pour le code Java et les architectures legacy.
  • Pour les nouveaux projets Kotlin, Google recommande StateFlow, mais LiveData reste une solution compatible pour les stacks hybrides.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi