onPause : qu'est-ce que c'est, sauvegarder l'état d'Activity sous Android

Auteur : IT Sectr Publié le : 2026-03-04 Temps de lecture : 10 min

onPause est une méthode du cycle de vie Android qui est appelée lorsqu'une Activity perd le focus d'entrée mais reste partiellement visible à l'écran. Le système appelle onPause avant qu'une nouvelle Activity n'arrive au premier plan, lors de l'ouverture d'une boîte de dialogue, lors de l'appui sur le bouton Applications récentes ou lors d'un appel entrant. Cette méthode est le dernier point garanti pour sauvegarder les données utilisateur, car après onStop et onDestroy, le système peut terminer le processus sans appels supplémentaires. À l'intérieur de onPause, le développeur sauvegarde les brouillons, met en pause les animations, libère la caméra et écrit l'état actuel de l'UI dans SharedPreferences. Pour plus de détails sur le cycle de vie complet d'une Activity, lisez l'article Activity Lifecycle.

Points clés

  • onPause — l'Activity perd le focus mais reste visible ; dernier point garanti pour sauvegarder les données
  • Sauvegarde d'état — dans onPause, les données critiques utilisateur sont sauvegardées : brouillons, texte dans les formulaires, progression
  • Libération de ressources — caméra, microphone, lecteur vidéo sont libérés dans onPause pour transfert à une autre application
  • Limite de temps — onPause doit se terminer en 100 ms ; le dépassement provoque ANR et retarde la transition
  • SharedPreferences.apply() — écriture asynchrone dans onPause ; commit() bloque le thread et peut causer ANR
  • onPause vs onStop — onPause en cas de visibilité partielle (dialogue), onStop en cas de masquage complet (autre Activity)
  • onSaveInstanceState — appelé après onPause pour sauvegarder l'état temporaire dans un Bundle

Qu'est-ce que onPause sous Android

onPause est la quatrième méthode du cycle de vie de l'Activity, appelée lorsque l'écran perd le focus d'entrée mais reste partiellement visible pour l'utilisateur. C'est un état de « transition » entre l'exécution active de l'application et son masquage. Le système appelle onPause dans les scénarios suivants : ouverture d'une autre Activity (un nouvel écran recouvre partiellement l'écran actuel), apparition d'une boîte de dialogue (Dialog, PopupWindow, Snackbar ne déclenchent pas onPause, mais DialogFragment le fait), appui sur le bouton Applications récentes, appel entrant, appui sur le bouton d'alimentation pour verrouiller l'écran.

La tâche principale de onPause est de préparer l'application à la possibilité d'être masquée ou détruite. C'est le dernier point du cycle de vie où le développeur peut être sûr que son code s'exécutera avant que le système ne poursuive la transition vers un autre composant. Après onPause, le système appelle onStop (si l'Activity est complètement masquée), après quoi le processus peut être terminé à tout moment sans notification supplémentaire.

Selon la documentation Android Developers (2025), onPause doit être aussi léger et rapide que possible. Tant que onPause n'a pas rendu le contrôle, le système ne peut pas démarrer l'Activity suivante — cela signifie que l'utilisateur voit un retard dans la transition d'écran. Google recommande de terminer onPause en moins de 100 millisecondes, et toutes les opérations longues (sauvegarde en base de données, écriture sur disque) doivent être effectuées de manière asynchrone via des coroutines ou apply().

onPause dans Activity

Dans une Activity, la méthode onPause est appelée chaque fois que l'écran cesse d'être actif mais peut continuer à être partiellement affiché. Un exemple typique : l'utilisateur ouvre l'application Cartes, appuie sur Partager la position, et une boîte de dialogue système de sélection d'application apparaît au-dessus des Cartes. L'Activity Cartes reçoit onPause mais reste visible sous le dialogue. Lorsque le dialogue se ferme, les Cartes reçoivent onResume sans appel à onStart (l'écran n'a pas été complètement masqué).

kotlin
class NoteEditorActivity : AppCompatActivity() {
    private var binding: ActivityNoteEditorBinding? = null
    private val prefs by lazy {
        getSharedPreferences("note_drafts", Context.MODE_PRIVATE)
    }

    override fun onPause() {
        super.onPause()

        // Sauvegarder le brouillon de note — de manière asynchrone
        prefs.edit()
            .putString("draft_title", binding?.titleInput?.text.toString())
            .putString("draft_body", binding?.bodyInput?.text.toString())
            .putLong("draft_timestamp", System.currentTimeMillis())
            .apply()

        // Mettre en pause la vidéo
        binding?.videoPlayer?.pause()

        // Libérer les ressources exclusives
        releaseCamera()
        releaseAudioFocus()
    }

    override fun onResume() {
        super.onResume()
        // Restaurer le brouillon
        binding?.titleInput?.setText(prefs.getString("draft_title", ""))
        binding?.bodyInput?.setText(prefs.getString("draft_body", ""))
        acquireCamera()
        acquireAudioFocus()
    }
}

L'exemple NoteEditorActivity démontre la gestion correcte de onPause : sauvegarde d'un brouillon dans SharedPreferences via apply(), mise en pause d'un fichier vidéo, libération de la caméra et du focus audio. Chaque appel est léger et rapide, sans bloquer le thread UI assez longtemps pour provoquer un ANR. Notez l'ordre : super.onPause() est appelé sur la première ligne — cela garantit que la logique système s'exécute même en cas d'exception dans le code utilisateur.

Sauvegarder l'état dans onPause

onPause est le dernier point où le développeur peut sauvegarder de manière fiable les données utilisateur avant que l'application ne soit masquée ou tuée par le système. Après onStop, le système peut terminer le processus si la mémoire est insuffisante, sans appeler onDestroy. La méthode onSaveInstanceState() est appelée après onPause, mais son Bundle n'est pas destiné au stockage à long terme — il ne vit que jusqu'au prochain onCreate.

SharedPreferences avec apply()

SharedPreferences avec apply() asynchrone est la manière optimale de sauvegarder de petites quantités de données dans onPause. Contrairement à commit(), qui écrit les données de manière synchrone sur le disque et retourne un booléen, apply() sauvegarde immédiatement les données en mémoire et planifie une écriture asynchrone sur le disque. Cela prend moins d'1 milliseconde sur le thread UI contre 10–100 millisecondes pour commit().

kotlin
override fun onPause() {
    super.onPause()

    // ❌ Mauvais : l'écriture synchrone bloque le thread
    // prefs.edit().putInt("score", score).commit()

    // ✅ Bon : écriture asynchrone
    prefs.edit().putInt("score", score).apply()

    // Pour les objets complexes — mise en cache dans ViewModel
    viewModel.saveState()
}

Room et coroutines

Pour les données structurées (SQLite via Room) dans onPause, on utilise des coroutines avec lifecycleScope. ViewModelScope annule automatiquement la coroutine lorsque le ViewModel est détruit, ce qui empêche les écritures dans une base de données fermée. L'écriture via Room avec des coroutines prend 5–15 millisecondes et ne bloque pas le thread UI.

kotlin
// Dans ViewModel :
fun saveDraft(title: String, body: String) {
    viewModelScope.launch(Dispatchers.IO) {
        noteDao.insert(NoteDraft(title = title, body = body))
    }
}

// Dans Activity.onPause :
viewModel.saveDraft(
    binding?.titleInput?.text.toString(),
    binding?.bodyInput?.text.toString()
)

onPause dans Fragment

onPause dans Fragment est appelé lorsque le Fragment cesse d'être actif mais peut rester visible. Cela se produit lorsque : un Fragment est remplacé par un autre Fragment via FragmentTransaction ; un Fragment n'est plus la page courante dans un ViewPager ; l'Activity contenant le Fragment reçoit onPause. L'interaction entre onPause de l'Activity et onPause du Fragment est strictement hiérarchique : d'abord l'Activity reçoit onPause, puis tous ses Fragments.

kotlin
class MapFragment : Fragment() {
    private var mapController: MapController? = null

    override fun onPause() {
        super.onPause()
        mapController?.stopFollowMode()
        binding?.mapContainer?.alpha = 0.7f
    }

    override fun onResume() {
        super.onResume()
        binding?.mapContainer?.alpha = 1.0f
        if (isVisible) {
            mapController?.startFollowMode()
        }
    }
}

Spécificités du travail avec les cartes dans onPause : Google Maps et Yandex Maps consomment des ressources GPU importantes en mode suivi actif. Lors de la perte de focus, il est logique de désactiver l'animation de la carte et de réduire la fréquence de mise à jour des marqueurs, et au retour du focus, de restaurer la fonctionnalité complète. Cela améliore les performances et réduit la consommation d'énergie lors du changement d'écrans.

onPause vs onStop : Différence et scénarios

L'une des confusions les plus fréquentes chez les développeurs Android débutants est de ne pas comprendre la différence entre onPause et onStop. Examinons chaque scénario et déterminons la méthode correcte.

ScénarioonPauseonStop
Ouverture d'une boîte de dialogueAppeléNon appelé
Ouverture d'une nouvelle Activity (non transparente)AppeléAppelé
Appui sur le bouton AccueilAppeléAppelé
Verrouillage de l'écranAppeléAppelé
Appel entrantAppeléAppelé
Activity transparente par-dessusAppeléNon appelé
Split Screen (demi-écran)AppeléNon appelé
PiP (Picture-in-Picture)AppeléNon appelé

La règle principale : onPause est appelé à toute perte de focus, onStop n'est appelé qu'en cas de perte complète de visibilité. Si l'Activity reste visible (même partiellement), onStop n'est pas appelé. Ceci est crucial pour les modes Split Screen, PiP et Activity transparente — ici onPause/onResume fonctionnent, mais onStart/onStop non.

Temporisation et performances de onPause

onPause est la méthode du cycle de vie la plus critique en termes de temps, car elle bloque le rendu de l'Activity suivante. Le système attend la fin de onPause de l'Activity actuelle avant d'afficher la nouvelle. Si onPause prend plus de 100 millisecondes, l'utilisateur remarque un retard dans la transition ; si plus de 5 secondes, le système affiche un ANR.

Recommandations de performances

Le Guide des performances Android de Google (2025) donne les recommandations suivantes pour onPause : n'effectuez pas de requêtes réseau — elles doivent être annulées ou déplacées vers WorkManager ; n'écrivez pas de gros fichiers sur le disque — utilisez BufferedWriter dans un thread d'arrière-plan ; n'exécutez pas de requêtes SQL complexes — les opérations Room doivent être asynchrones via des coroutines ; évitez de créer de nouveaux objets — le garbage collection dans onPause aggrave le retard ; utilisez apply() au lieu de commit() pour SharedPreferences.

kotlin
override fun onPause() {
    super.onPause()

    // ❌ Mauvais : la requête HTTP bloque l'UI
    // val response = api.syncSave(data).execute()

    // ❌ Mauvais : écriture synchrone dans un fichier
    // FileOutputStream(file).write(data)

    // ✅ Bon : sauvegarde asynchrone
    lifecycleScope.launch {
        withContext(Dispatchers.IO) {
            api.saveData(data)
            fileDao.write(data)
        }
    }

    // ✅ Bon : écriture légère dans SharedPreferences
    prefs.edit().putString("key", value).apply()
}

Le profilage de onPause via Android Studio Profiler (trace CPU) montre le temps d'exécution exact. Si onPause prend plus de 100 ms, Profiler surligne la méthode en jaune, et plus de 500 ms en rouge. Dans les projets commerciaux chez IT Sectr, nous utilisons des tests Macrobenchmark qui vérifient automatiquement le temps de transition entre Activities et signalent les régressions de performances dans le pipeline CI.

Erreurs courantes dans onPause

Même les développeurs expérimentés commettent des erreurs dans onPause. Examinons cinq problèmes typiques et leurs solutions.

Écriture synchrone en base de données

Appeler Room DAO avec une requête synchrone (.executeAsObservable() sans coroutines) dans onPause bloque le thread UI pendant 10–50 ms. Si un GC ou une contention d'écriture survient au même moment, le retard peut atteindre 200–500 ms. Solution : utilisez des coroutines avec Dispatchers.IO ou apply() pour SharedPreferences.

Enregistrement de nouveaux écouteurs

onPause n'est pas l'endroit pour enregistrer des écouteurs. Si vous enregistrez un BroadcastReceiver dans onPause, il restera actif alors que l'Activity n'est plus visible. L'enregistrement ne doit avoir lieu que dans onStart/onResume, et dans onPause/onStop — seulement le désabonnement. L'exception concerne les API basées sur Intent qui nécessitent un enregistrement avant l'appel.

Ignorer les exceptions

Si une exception non gérée se produit dans onPause, le système n'appelle pas onStop et onDestroy. L'Activity reste bloquée dans un état indéfini, et onResume au retour peut ne pas restaurer correctement les ressources libérées. Solution : encapsulez les opérations critiques dans try/catch avec journalisation via Log.e().

Sauvegarde de données redondantes

Il n'est pas nécessaire de sauvegarder dans onPause des données qui peuvent être facilement restaurées. Par exemple, les résultats de requêtes API sont mis en cache dans Room ou DataStore au moment de la récupération, pas dans onPause. Sauvegardez uniquement ce que l'utilisateur a saisi manuellement et qui ne peut pas être restauré automatiquement — texte dans les champs, éléments sélectionnés, position de défilement.

Oubli de super.onPause()

super.onPause() doit être appelé, mais contrairement à onCreate, son omission ne provoque pas un crash immédiat. Le système « pardonne » l'absence de super dans onPause, mais la machine d'état interne entre dans un état incorrect. Le prochain appel onResume peut ne pas restaurer le focus d'entrée, laissant l'Activity « gelée ». Appelez toujours super.onPause() le plus tôt possible.

Questions fréquentes

Que se passe-t-il si on appelle finish() dans onPause ?

Appeler finish() dans onPause terminera l'Activity immédiatement après le retour de la méthode. C'est un scénario valide si l'écran doit être fermé lors de la perte de focus (par exemple, un écran d'autorisation lors de la minimisation de l'application). Cependant, finish() déclenche le cycle complet de terminaison : onStop onDestroy, ce qui ajoute un retard à la transition. Utilisez finish() dans onPause uniquement lorsque c'est vraiment nécessaire.

En quoi onPause diffère-t-il de onSaveInstanceState ?

onPause est pour sauvegarder les données qui doivent survivre à la terminaison du processus (brouillons dans SharedPreferences/Room). onSaveInstanceState est pour sauvegarder l'état temporaire de l'UI qui n'est nécessaire que jusqu'au prochain onCreate (position de défilement, onglet sélectionné). Le Bundle de onSaveInstanceState n'est pas conservé lorsque l'application est complètement terminée — il n'existe qu'en mémoire. Les données de onPause sont sauvegardées sur le disque et survivent à un redémarrage.

Peut-on ouvrir une boîte de dialogue dans onPause ?

Déconseillé. Ouvrir une boîte de dialogue ou une popup dans onPause provoque une WindowLeakException si l'Activity est déjà terminée. Si vous devez afficher une notification lors de la perte de focus, utilisez NotificationManager (notifications système) — c'est sûr et attendu par l'utilisateur. Pour les actions différées, utilisez AlarmManager ou WorkManager.

Pourquoi onPause est un point de sauvegarde garanti, mais pas onStop ?

onPause est garanti d'être appelé avant que l'Activity ne cesse d'être active. onStop peut ne pas être appelé si le système tue le processus pour libérer de la mémoire — dans ce cas, onDestroy n'est pas non plus appelé. onPause est la seule méthode après onResume qui est toujours appelée, quelle que soit la raison de la perte de focus. Par conséquent, toutes les données critiques sont sauvegardées précisément dans onPause.

Comment tester onPause dans des tests unitaires ?

Pour tester onPause, on utilise Robolectric ou FragmentScenario d'AndroidX Test. FragmentScenario.create() moveToState(State.STARTED) moveToState(State.RESUMED) moveToState(State.STARTED) appelle onPause séquentiellement. Ensuite, on vérifie que les données ont été sauvegardées dans SharedPreferences ou que la caméra a été libérée via un objet mock. Robolectric 4.12+ prend en charge l'émulation de onPause/onResume sans périphérique physique.

Résumé

  • onPause — l'Activity perd le focus d'entrée mais reste partiellement visible ; dernier point garanti pour sauvegarder les données
  • Sauvegarde — SharedPreferences.apply() ou Room via des coroutines ; commit() et opérations synchrones sont interdits
  • Libération de ressources — caméra, focus audio, lecteur vidéo sont libérés dans onPause pour transfert à une autre application
  • Limite de 100 ms — onPause bloque le rendu de l'Activity suivante ; le dépassement de la limite provoque ANR
  • onPause vs onStop — onPause en cas de perte de focus (visibilité conservée), onStop en cas de masquage complet
  • Fragment.onPause — appel hiérarchique après Activity.onPause ; spécificités pour les cartes et ViewPager
  • Erreurs courantes — écriture synchrone, enregistrement d'écouteurs, ignorance de try/catch, sauvegarde redondante
  • super.onPause() — appeler le plus tôt possible ; omission ne cause pas de crash mais casse la machine d'état

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