onPause — este metoda ciclului de viață Android care este apelată atunci când Activity pierde focalizarea de intrare, dar rămâne parțial vizibilă pe ecran. Sistemul apelează onPause înainte ca o nouă Activity să iasă în prim-plan, la deschiderea unei ferestre de dialog, la apăsarea butonului „Aplicații recente” sau la un apel primit. Această metodă — ultimul punct garantat pentru salvarea datelor utilizatorului, deoarece după onStop și onDestroy sistemul poate termina procesul fără apeluri suplimentare. În onPause dezvoltatorul salvează ciorne, suspendă animațiile, eliberează camera și scrie starea curentă a UI în SharedPreferences. Mai multe despre ciclul de viață complet al Activity citiți în articolul Activity Lifecycle.
Principalele
onPause — a patra metodă a ciclului de viață Activity, care este apelată când ecranul pierde focalizarea de intrare, dar rămâne parțial vizibil pentru utilizator. Aceasta este o stare „de tranziție” între munca activă a aplicației și ascunderea ei. Sistemul apelează onPause în următoarele scenarii: deschiderea unei alte Activity (un ecran nou acoperă cel curent), apariția unei ferestre de dialog (Dialog, PopupWindow, Snackbar nu apelează onPause, dar DialogFragment — da), apăsarea butonului „Aplicații recente”, apel primit, apăsarea butonului „Alimentare” pentru blocarea ecranului.
Sarcina principală a onPause — pregătirea aplicației pentru posibila ascundere sau distrugere. Acesta este ultimul punct în ciclul de viață unde dezvoltatorul poate fi sigur că codul său se va executa înainte ca sistemul să continue tranziția către o altă componentă. După onPause sistemul apelează onStop (dacă Activity se ascunde complet), după care distrugerea procesului poate avea loc în orice moment fără notificări suplimentare.
Conform documentației Android Developers (2025), onPause trebuie să fie cât mai ușor și rapid. Până când onPause nu returnează controlul, sistemul nu poate porni următoarea Activity — aceasta înseamnă că utilizatorul vede o întârziere a tranziției între ecrane. Google recomandă finalizarea onPause în mai puțin de 100 de milisecunde, iar toate operațiile lungi (salvarea în baza de date, scrierea pe disc) să fie executate asincron prin corutine sau apply().
În Activity, metoda onPause este apelată de fiecare dată când ecranul încetează să fie activ, dar poate continua să fie afișat parțial. Exemplu tipic: utilizatorul deschide aplicația „Hărți”, apasă „Partajează locația”, și deasupra Hărților se deschide un dialog de sistem pentru selectarea aplicației. Activity Hărților primește onPause, dar rămâne vizibilă sub dialog. Când dialogul se închide, Hărțile primesc onResume fără apelarea onStart (ecranul nu a fost ascuns complet).
class NoteEditorActivity : AppCompatActivity() {
private var binding: ActivityNoteEditorBinding? = null
private val prefs by lazy {
getSharedPreferences("note_drafts", Context.MODE_PRIVATE)
}
override fun onPause() {
super.onPause()
// Salvăm ciorna notiței — asincron
prefs.edit()
.putString("draft_title", binding?.titleInput?.text.toString())
.putString("draft_body", binding?.bodyInput?.text.toString())
.putLong("draft_timestamp", System.currentTimeMillis())
.apply()
// Suspendăm videoclipul
binding?.videoPlayer?.pause()
// Eliberăm resursele exclusive
releaseCamera()
releaseAudioFocus()
}
override fun onResume() {
super.onResume()
// Restaurăm ciorna
binding?.titleInput?.setText(prefs.getString("draft_title", ""))
binding?.bodyInput?.setText(prefs.getString("draft_body", ""))
acquireCamera()
acquireAudioFocus()
}
}
Exemplul NoteEditorActivity demonstrează lucrul corect cu onPause: salvarea ciornei în SharedPreferences prin apply(), suspendarea fișierului video, eliberarea camerei și a focalizării audio. Fiecare apel — ușor și rapid, fără a bloca firul UI suficient pentru ANR. Atenție la ordine: super.onPause() este apelat în prima linie — aceasta garantează că logica de sistem se va executa chiar și la o excepție în codul utilizatorului.
onPause — ultimul punct unde dezvoltatorul poate salva garantat datele utilizatorului înainte ca aplicația să fie ascunsă sau ucisă de sistem. După onStop sistemul poate distruge procesul la lipsa de memorie fără a apela onDestroy. Metoda onSaveInstanceState() este apelată după onPause, dar Bundle-ul său nu este destinat stocării pe termen lung — trăiește doar până la următorul onCreate.
SharedPreferences cu apply() asincron — modalitatea optimă de salvare a volumelor mici de date în onPause. Spre deosebire de commit(), care scrie sincron datele pe disc și returnează boolean, apply() salvează imediat datele în memorie și planifică o scriere asincronă pe disc. Aceasta durează mai puțin de 1 milisecundă în firul UI față de 10–100 milisecunde pentru commit().
override fun onPause() {
super.onPause()
// ❌ Rău: scrierea sincronă blochează firul
// prefs.edit().putInt("score", score).commit()
// ✅ Bine: scrierea asincronă
prefs.edit().putInt("score", score).apply()
// Pentru obiecte complexe — stocare în cache în ViewModel
viewModel.saveState()
}
Pentru date structurate (SQLite prin Room) în onPause se folosesc corutine cu lifecycleScope. ViewModelScope anulează automat corutina la distrugerea ViewModel, prevenind scrierea într-o bază de date închisă. Scrierea prin Room cu corutine durează 5–15 milisecunde și nu blochează firul UI.
// În ViewModel:
fun saveDraft(title: String, body: String) {
viewModelScope.launch(Dispatchers.IO) {
noteDao.insert(NoteDraft(title = title, body = body))
}
}
// În Activity.onPause:
viewModel.saveDraft(
binding?.titleInput?.text.toString(),
binding?.bodyInput?.text.toString()
)
onPause în Fragment este apelat când Fragmentul încetează să fie activ, dar poate rămâne vizibil. Aceasta se întâmplă când: Fragmentul este înlocuit cu un alt Fragment prin FragmentTransaction; Fragmentul încetează să fie pagina curentă în ViewPager; Activity care conține Fragmentul primește onPause. Interacțiunea între onPause al Activity și onPause al Fragmentului este strict ierarhică: mai întâi onPause primește Activity, apoi toate Fragmentele sale.
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()
}
}
}
Specificul lucrului cu hărțile în onPause: Google Maps și Yandex Maps consumă resurse GPU semnificative în modul de urmărire activ (follow mode). La pierderea focalizării, are sens să dezactivați animația hărții și să reduceți frecvența de actualizare a marcajelor, iar la revenirea focalizării — să restabiliți funcționalitatea completă. Aceasta îmbunătățește performanța și reduce consumul de energie la comutarea între ecrane.
Una dintre cele mai frecvente confuzii la dezvoltatorii Android începători — neînțelegerea diferenței dintre onPause și onStop. Să examinăm fiecare scenariu și să determinăm metoda corectă.
| Scenariu | onPause | onStop |
|---|---|---|
| Deschiderea ferestrei de dialog | Apelat | Neapelat |
| Deschiderea unei noi Activity (netransparente) | Apelat | Apelat |
| Apăsarea butonului „Acasă” | Apelat | Apelat |
| Blocarea ecranului | Apelat | Apelat |
| Apel primit | Apelat | Apelat |
| Activity transparentă peste cea curentă | Apelat | Neapelat |
| Split Screen (jumătate de ecran) | Apelat | Neapelat |
| PiP (Picture-in-Picture) | Apelat | Neapelat |
Regula principală: onPause este apelat la orice pierdere a focalizării, onStop — doar la pierderea completă a vizibilității. Dacă Activity rămâne vizibilă (chiar și parțial), onStop nu este apelat. Acest lucru este critic pentru modurile Split Screen, PiP și Activity transparente — aici onPause/onResume funcționează, iar onStart/onStop — nu.
onPause — cea mai critică metodă din punct de vedere al timpului a ciclului de viață, deoarece blochează randarea următoarei Activity. Sistemul așteaptă finalizarea onPause a Activity curente înainte de a arăta una nouă. Dacă onPause se execută mai mult de 100 de milisecunde, utilizatorul observă o întârziere a tranziției; dacă mai mult de 5 secunde — sistemul arată ANR.
Ghidul de performanță Android Google (2025) oferă următoarele recomandări pentru onPause: nu executați cereri de rețea — acestea trebuie anulate sau mutate în WorkManager; nu scrieți fișiere mari pe disc — utilizați BufferedWriter într-un fir de fundal; nu executați interogări SQL complexe — operațiile Room trebuie să fie asincrone prin corutine; evitați crearea de obiecte noi — garbage collection în onPause agravează întârzierea; utilizați apply() în loc de commit() pentru SharedPreferences.
override fun onPause() {
super.onPause()
// ❌ Rău: cererea HTTP blochează UI
// val response = api.syncSave(data).execute()
// ❌ Rău: scrierea sincronă în fișier
// FileOutputStream(file).write(data)
// ✅ Bine: salvarea asincronă
lifecycleScope.launch {
withContext(Dispatchers.IO) {
api.saveData(data)
fileDao.write(data)
}
}
// ✅ Bine: scrierea ușoară în SharedPreferences
prefs.edit().putString("key", value).apply()
}
Profilarea onPause prin Android Studio Profiler (graficul CPU) arată timpul exact de execuție. Dacă onPause durează mai mult de 100 ms, Profiler evidențiază metoda cu galben, iar mai mult de 500 ms — cu roșu. În proiectele comerciale IT Sectr folosim teste Macrobenchmark care verifică automat timpul de tranziție între Activity și semnalează regresia de performanță în pipeline-ul CI.
Chiar și dezvoltatorii experimentați fac greșeli în onPause. Să examinăm cinci probleme tipice și soluțiile lor.
Apelarea Room DAO cu o interogare sincronă (.executeAsObservable() fără corutine) în onPause blochează firul UI timp de 10–50 ms. Dacă în acest moment are loc GC sau concurență pentru scrierea în baza de date, întârzierea poate ajunge la 200–500 ms. Soluție: utilizați corutine cu Dispatchers.IO sau apply() pentru SharedPreferences.
onPause nu este locul pentru înregistrarea ascultătorilor. Dacă înregistrați un BroadcastReceiver în onPause, acesta va rămâne activ când Activity nu mai este vizibilă. Înregistrarea trebuie să fie doar în onStart/onResume, iar în onPause/onStop — doar dezabonare. Excepție — API-uri Intent-driven care necesită înregistrare înainte de apelare.
Dacă în onPause apare o excepție negestionată, sistemul nu apelează onStop și onDestroy. Activity rămâne blocată într-o stare nedeterminată, iar onResume la revenire poate să nu restaureze corect resursele eliberate. Soluție: înfășurați operațiile critice în try/catch cu logare prin Log.e().
Nu este necesar să salvați în onPause date care pot fi ușor restaurate. De exemplu, rezultatele cererilor API sunt stocate în cache în Room sau DataStore în momentul primirii, nu în onPause. Salvați doar ceea ce utilizatorul a introdus manual și nu poate restaura automat — text în câmpuri, elemente selectate, poziția scroll-ului.
super.onPause() trebuie apelat, dar spre deosebire de onCreate, lipsa lui nu cauzează un crash imediat. Sistemul „iertă” omiterea super în onPause, dar mașina de stări internă trece într-o stare incorectă. Următorul apel onResume poate să nu restabilească focalizarea de intrare, iar Activity rămâne „înghețată”. Apelați întotdeauna super.onPause() cât mai devreme posibil.
Întrebări frecvente
Apelarea finish() în onPause va încheia Activity imediat după revenirea din metodă. Acesta este un scenariu corect dacă la pierderea focalizării trebuie închis ecranul (de exemplu, ecranul de autentificare la minimizarea aplicației). Cu toate acestea, finish() pornește ciclul complet de încheiere: onStop → onDestroy, ceea ce adaugă o întârziere la tranziție. Utilizați finish() în onPause doar când este cu adevărat necesar.
onPause — pentru salvarea datelor care trebuie să supraviețuiască încheierii procesului (ciorne în SharedPreferences/Room). onSaveInstanceState — pentru salvarea stării temporare a UI care este necesară doar până la următorul onCreate (poziția scroll-ului, fila selectată). Bundle-ul onSaveInstanceState nu se salvează la încheierea completă a aplicației — există doar în memorie. Datele onPause sunt salvate pe disc și supraviețuiesc repornirii.
Nu este recomandat. Deschiderea unui dialog sau a unei ferestre pop-up în onPause duce la WindowLeakException dacă Activity este deja încheiată. Dacă trebuie să afișați o notificare la pierderea focalizării, utilizați NotificationManager (notificări de sistem) — este sigur și așteptat de utilizator. Pentru acțiuni amânate, utilizați AlarmManager sau WorkManager.
onPause este garantat apelat înainte ca Activity să înceteze să fie activă. onStop poate să nu fie apelat dacă sistemul ucide procesul pentru a elibera memoria — în acest caz onDestroy nu este apelat nici el. onPause — singura metodă după onResume care este apelată întotdeauna, indiferent de cauza pierderii focalizării. De aceea toate datele critice se salvează exact în onPause.
Pentru testarea onPause se folosește Robolectric sau FragmentScenario din AndroidX Test. FragmentScenario.create() → moveToState(State.STARTED) → moveToState(State.RESUMED) → moveToState(State.STARTED) apelează secvențial onPause. Apoi se verifică dacă datele au fost salvate în SharedPreferences sau dacă camera a fost eliberată printr-un obiect mock. Robolectric 4.12+ suportă emularea onPause/onResume fără dispozitiv fizic.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și