onPause — is de levenscyclusmethode van Android die wordt aangeroepen wanneer Activity de invoerfocus verliest, maar gedeeltelijk zichtbaar blijft op het scherm. Het systeem roept onPause aan voordat een nieuwe Activity op de voorgrond komt, bij het openen van een dialoogvenster, bij het indrukken van de knop „Recente apps” of bij een inkomend gesprek. Deze methode is het laatste gegarandeerde punt voor het opslaan van gebruikersgegevens, omdat het systeem na onStop en onDestroy het proces kan beëindigen zonder extra aanroepen. Binnen onPause bewaart de ontwikkelaar concepten, pauzeert animaties, geeft de camera vrij en schrijft de huidige UI-status naar SharedPreferences. Lees meer over de volledige Activity-levenscyclus in het artikel Activity Lifecycle.
Belangrijkste
onPause — de vierde methode van de Activity-levenscyclus, die wordt aangeroepen wanneer het scherm de invoerfocus verliest, maar gedeeltelijk zichtbaar blijft voor de gebruiker. Dit is een „overgangs”toestand tussen het actieve werk van de app en het verbergen ervan. Het systeem roept onPause aan in de volgende scenario's: openen van een andere Activity (nieuw scherm bedekt het huidige), verschijnen van een dialoogvenster (Dialog, PopupWindow, Snackbar roepen onPause niet aan, maar DialogFragment wel), indrukken van de knop „Recente apps”, inkomend gesprek, indrukken van de aan/uit-knop om het scherm te vergrendelen.
De hoofdtaak van onPause is de app voorbereiden op de mogelijkheid dat deze wordt verborgen of vernietigd. Dit is het laatste punt in de levenscyclus waar de ontwikkelaar er zeker van kan zijn dat zijn code wordt uitgevoerd voordat het systeem verder gaat naar een andere component. Na onPause roept het systeem onStop aan (als Activity volledig wordt verborgen), waarna vernietiging van het proces op elk moment kan plaatsvinden zonder extra meldingen.
Volgens de Android Developers-documentatie (2025) moet onPause zo licht en snel mogelijk zijn. Zolang onPause de controle niet teruggeeft, kan het systeem de volgende Activity niet starten — dit betekent dat de gebruiker een vertraging in de overgang tussen schermen ziet. Google raadt aan onPause in minder dan 100 milliseconden te voltooien en alle langdurige bewerkingen (opslaan in database, schrijven naar schijf) asynchroon uit te voeren via coroutines of apply().
In Activity wordt de onPause-methode aangeroepen telkens wanneer het scherm niet langer actief is, maar nog gedeeltelijk kan worden weergegeven. Typisch voorbeeld: de gebruiker opent de app „Kaarten”, drukt op „Locatie delen” en boven de Kaarten opent een systeemdialoog voor het selecteren van een app. De Activity van Kaarten krijgt onPause, maar blijft zichtbaar onder de dialoog. Wanneer de dialoog wordt gesloten, krijgen Kaarten onResume zonder aanroep van onStart (het scherm was niet volledig verborgen).
class NoteEditorActivity : AppCompatActivity() {
private var binding: ActivityNoteEditorBinding? = null
private val prefs by lazy {
getSharedPreferences("note_drafts", Context.MODE_PRIVATE)
}
override fun onPause() {
super.onPause()
// Concept van notitie opslaan — asynchroon
prefs.edit()
.putString("draft_title", binding?.titleInput?.text.toString())
.putString("draft_body", binding?.bodyInput?.text.toString())
.putLong("draft_timestamp", System.currentTimeMillis())
.apply()
// Video pauzeren
binding?.videoPlayer?.pause()
// Exclusieve bronnen vrijgeven
releaseCamera()
releaseAudioFocus()
}
override fun onResume() {
super.onResume()
// Concept herstellen
binding?.titleInput?.setText(prefs.getString("draft_title", ""))
binding?.bodyInput?.setText(prefs.getString("draft_body", ""))
acquireCamera()
acquireAudioFocus()
}
}
Het voorbeeld NoteEditorActivity demonstreert correct werken met onPause: bewaren van het concept in SharedPreferences via apply(), pauzeren van het videobestand, vrijgeven van de camera en audiofocus. Elke aanroep is licht en snel, zonder de UI-thread voldoende te blokkeren voor ANR. Let op de volgorde: super.onPause() wordt in de eerste regel aangeroepen — dit garandeert dat de systeemlogica wordt uitgevoerd, zelfs bij een uitzondering in de gebruikerscode.
onPause — het laatste punt waar de ontwikkelaar gegarandeerd gebruikersgegevens kan opslaan voordat de app wordt verborgen of door het systeem wordt beëindigd. Na onStop kan het systeem het proces vernietigen bij geheugengebrek zonder onDestroy aan te roepen. De methode onSaveInstanceState() wordt na onPause aangeroepen, maar de Bundle ervan is niet bedoeld voor langdurige opslag — deze leeft alleen tot de volgende onCreate.
SharedPreferences met asynchrone apply() — de optimale manier om kleine hoeveelheden gegevens op te slaan in onPause. In tegenstelling tot commit(), die synchroon gegevens naar schijf schrijft en boolean retourneert, slaat apply() onmiddellijk gegevens in het geheugen op en plant het een asynchrone schrijfactie naar schijf. Dit duurt minder dan 1 milliseconde in de UI-thread tegenover 10–100 milliseconden voor commit().
override fun onPause() {
super.onPause()
// ❌ Slecht: synchroon schrijven blokkeert thread
// prefs.edit().putInt("score", score).commit()
// ✅ Goed: asynchroon schrijven
prefs.edit().putInt("score", score).apply()
// Voor complexe objecten — caching in ViewModel
viewModel.saveState()
}
Voor gestructureerde gegevens (SQLite via Room) in onPause worden coroutines met lifecycleScope gebruikt. ViewModelScope annuleert automatisch de coroutine bij vernietiging van de ViewModel, wat schrijven naar een gesloten database voorkomt. Schrijven via Room met coroutines duurt 5–15 milliseconden en blokkeert de UI-thread niet.
// In ViewModel:
fun saveDraft(title: String, body: String) {
viewModelScope.launch(Dispatchers.IO) {
noteDao.insert(NoteDraft(title = title, body = body))
}
}
// In Activity.onPause:
viewModel.saveDraft(
binding?.titleInput?.text.toString(),
binding?.bodyInput?.text.toString()
)
onPause in Fragment wordt aangeroepen wanneer het Fragment niet langer actief is, maar zichtbaar kan blijven. Dit gebeurt wanneer: het Fragment wordt vervangen door een ander Fragment via FragmentTransaction; het Fragment niet langer de huidige pagina in ViewPager is; de Activity die het Fragment bevat onPause krijgt. De interactie tussen onPause van Activity en onPause van Fragment is strikt hiërarchisch: eerst krijgt Activity onPause, dan al zijn Fragmenten.
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()
}
}
}
Specificiteit van werken met kaarten in onPause: Google Maps en Yandex Maps verbruiken aanzienlijke GPU-bronnen in de actieve volgmodus (follow mode). Bij focusverlies is het zinvol om de kaartanimatie uit te schakelen en de vernieuwingsfrequentie van markers te verlagen, en bij focushervatting de volledige functionaliteit te herstellen. Dit verbetert de prestaties en vermindert het energieverbruik bij het schakelen tussen schermen.
Een van de meest voorkomende verwarringen bij beginnende Android-ontwikkelaars is het niet begrijpen van het verschil tussen onPause en onStop. Laten we elk scenario bekijken en de juiste methode bepalen.
| Scenario | onPause | onStop |
|---|---|---|
| Openen van een dialoogvenster | Aangeroepen | Niet aangeroepen |
| Openen van een nieuwe Activity (niet transparant) | Aangeroepen | Aangeroepen |
| Indrukken van de knop „Home” | Aangeroepen | Aangeroepen |
| Scherm vergrendelen | Aangeroepen | Aangeroepen |
| Inkomend gesprek | Aangeroepen | Aangeroepen |
| Transparante Activity boven huidige | Aangeroepen | Niet aangeroepen |
| Split Screen (helft scherm) | Aangeroepen | Niet aangeroepen |
| PiP (Picture-in-Picture) | Aangeroepen | Niet aangeroepen |
Hoofdregel: onPause wordt aangeroepen bij elk focusverlies, onStop — alleen bij volledig verlies van zichtbaarheid. Als Activity zichtbaar blijft (zelfs gedeeltelijk), wordt onStop niet aangeroepen. Dit is cruciaal voor de modi Split Screen, PiP en transparante Activity's — hier werken onPause/onResume, maar onStart/onStop niet.
onPause — de meest kritieke methode qua tijd in de levenscyclus, omdat deze het renderen van de volgende Activity blokkeert. Het systeem wacht op voltooiing van onPause van de huidige Activity voordat het een nieuwe toont. Als onPause langer dan 100 milliseconden duurt, merkt de gebruiker een vertraging in de overgang; als het langer dan 5 seconden duurt, toont het systeem ANR.
De Google Android Performance Guide (2025) geeft de volgende aanbevelingen voor onPause: voer geen netwerkverzoeken uit — deze moeten worden geannuleerd of verplaatst naar WorkManager; schrijf geen grote bestanden naar schijf — gebruik BufferedWriter in een achtergrondthread; voer geen complexe SQL-query's uit — Room-bewerkingen moeten asynchroon zijn via coroutines; vermijd het maken van nieuwe objecten — garbage collection in onPause verergert de vertraging; gebruik apply() in plaats van commit() voor SharedPreferences.
override fun onPause() {
super.onPause()
// ❌ Slecht: HTTP-verzoek blokkeert UI
// val response = api.syncSave(data).execute()
// ❌ Slecht: synchroon schrijven naar bestand
// FileOutputStream(file).write(data)
// ✅ Goed: asynchroon opslaan
lifecycleScope.launch {
withContext(Dispatchers.IO) {
api.saveData(data)
fileDao.write(data)
}
}
// ✅ Goed: licht schrijven naar SharedPreferences
prefs.edit().putString("key", value).apply()
}
Het profileren van onPause via Android Studio Profiler (CPU-grafiek) toont de exacte uitvoeringstijd. Als onPause meer dan 100 ms duurt, markeert Profiler de methode geel, en meer dan 500 ms — rood. In commerciële projecten van IT Sectr gebruiken we Macrobenchmark-tests die automatisch de overgangstijd tussen Activity's controleren en prestatieregressie signaleren in de CI-pipeline.
Zelfs ervaren ontwikkelaars maken fouten in onPause. Laten we vijf typische problemen en hun oplossingen bekijken.
Het aanroepen van Room DAO met een synchrone query (.executeAsObservable() zonder coroutines) in onPause blokkeert de UI-thread gedurende 10–50 ms. Als op dat moment GC of concurrentie voor het schrijven naar de database plaatsvindt, kan de vertraging oplopen tot 200–500 ms. Oplossing: gebruik coroutines met Dispatchers.IO of apply() voor SharedPreferences.
onPause is niet de plaats voor het registreren van listeners. Als u een BroadcastReceiver registreert in onPause, blijft deze actief wanneer de Activity niet meer zichtbaar is. Registratie mag alleen plaatsvinden in onStart/onResume, en in onPause/onStop — alleen uitschrijven. Uitzondering — Intent-driven API's die registratie vereisen voor aanroep.
Als er in onPause een onverwerkte uitzondering optreedt, roept het systeem onStop en onDestroy niet aan. De Activity blijft hangen in een onbepaalde toestand en onResume bij terugkeer kan de vrijgegeven bronnen niet correct herstellen. Oplossing: omhul kritieke bewerkingen met try/catch en log via Log.e().
Het is niet nodig om in onPause gegevens op te slaan die gemakkelijk kunnen worden hersteld. Bijvoorbeeld, resultaten van API-verzoeken worden in cache opgeslagen in Room of DataStore op het moment van ontvangst, niet in onPause. Sla alleen op wat de gebruiker handmatig heeft ingevoerd en niet automatisch kan worden hersteld — tekst in velden, geselecteerde elementen, scrollpositie.
super.onPause() moet worden aangeroepen, maar in tegenstelling tot onCreate veroorzaakt het ontbreken ervan geen onmiddellijke crash. Het systeem 'vergeeft' het overslaan van super in onPause, maar de interne toestandsmachine gaat naar een onjuiste toestand. De volgende aanroep van onResume kan de invoerfocus mogelijk niet herstellen en de Activity blijft 'bevroren'. Roep altijd super.onPause() zo vroeg mogelijk aan.
Veelgestelde vragen
Het aanroepen van finish() in onPause beëindigt de Activity onmiddellijk na terugkeer uit de methode. Dit is een correct scenario als bij focusverlies het scherm moet worden gesloten (bijvoorbeeld het authenticatiescherm bij het minimaliseren van de app). Echter, finish() start de volledige beëindigingscyclus: onStop → onDestroy, wat vertraging toevoegt aan de overgang. Gebruik finish() in onPause alleen wanneer het echt nodig is.
onPause — voor het opslaan van gegevens die het beëindigen van het proces moeten overleven (concepten in SharedPreferences/Room). onSaveInstanceState — voor het opslaan van tijdelijke UI-status die alleen nodig is tot de volgende onCreate (scrollpositie, geselecteerd tabblad). De Bundle van onSaveInstanceState wordt niet bewaard bij volledige beëindiging van de app — deze bestaat alleen in het geheugen. onPause-gegevens worden op schijf opgeslagen en overleven een herstart.
Niet aanbevolen. Het openen van een dialoog of pop-upvenster in onPause leidt tot WindowLeakException als de Activity al is beëindigd. Als u een melding moet tonen bij focusverlies, gebruik dan NotificationManager (systeemmeldingen) — dit is veilig en wordt verwacht door de gebruiker. Voor uitgestelde acties gebruikt u AlarmManager of WorkManager.
onPause wordt gegarandeerd aangeroepen voordat Activity niet langer actief is. onStop wordt mogelijk niet aangeroepen als het systeem het proces beëindigt om geheugen vrij te maken — in dat geval wordt onDestroy ook niet aangeroepen. onPause is de enige methode na onResume die altijd wordt aangeroepen, ongeacht de reden van focusverlies. Daarom worden alle kritieke gegevens precies in onPause opgeslagen.
Voor het testen van onPause wordt Robolectric of FragmentScenario van AndroidX Test gebruikt. FragmentScenario.create() → moveToState(State.STARTED) → moveToState(State.RESUMED) → moveToState(State.STARTED) roept sequentieel onPause aan. Vervolgens wordt gecontroleerd of de gegevens zijn opgeslagen in SharedPreferences of dat de camera is vrijgegeven via een mock-object. Robolectric 4.12+ ondersteunt emulatie van onPause/onResume zonder fysiek apparaat.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook