onPause is an Android lifecycle method that is called when an Activity loses input focus but remains partially visible on the screen. The system calls onPause before a new Activity comes to the foreground, when a dialog opens, when the Recent Apps button is pressed, or when an incoming call arrives. This method is the last guaranteed point for saving user data, since after onStop and onDestroy the system may terminate the process without additional calls. Inside onPause, the developer saves drafts, pauses animations, releases the camera, and writes the current UI state to SharedPreferences. For more details on the full Activity lifecycle, read the article Activity Lifecycle.
Key Takeaways
onPause is the fourth method of the Activity lifecycle, called when the screen loses input focus but remains partially visible to the user. It is a “transitional” state between the app actively running and being hidden. The system calls onPause in the following scenarios: opening another Activity (a new screen partially covers the current one), showing a dialog window (Dialog, PopupWindow, Snackbar do not trigger onPause, but DialogFragment does), pressing the Recent Apps button, an incoming call, pressing the Power button to lock the screen.
The main purpose of onPause is to prepare the app for the possibility of being hidden or destroyed. This is the last point in the lifecycle where the developer can be sure their code will execute before the system proceeds to transition to another component. After onPause, the system calls onStop (if the Activity is fully hidden), after which the process can be terminated at any time without further notification.
According to the Android Developers documentation (2025), onPause should be as lightweight and fast as possible. While onPause has not returned control, the system cannot start the next Activity — meaning the user sees a delay in the screen transition. Google recommends completing onPause within less than 100 milliseconds, and all long-running operations (database saves, disk writes) should be performed asynchronously through coroutines or apply().
In an Activity, the onPause method is called every time the screen ceases to be active but may continue to be partially displayed. A typical example: the user opens the Maps app, taps Share Location, and a system app selection dialog appears on top of Maps. The Maps Activity receives onPause but remains visible beneath the dialog. When the dialog closes, Maps receives onResume without onStart being called (the screen was not fully hidden).
class NoteEditorActivity : AppCompatActivity() {
private var binding: ActivityNoteEditorBinding? = null
private val prefs by lazy {
getSharedPreferences("note_drafts", Context.MODE_PRIVATE)
}
override fun onPause() {
super.onPause()
// Save note draft — asynchronously
prefs.edit()
.putString("draft_title", binding?.titleInput?.text.toString())
.putString("draft_body", binding?.bodyInput?.text.toString())
.putLong("draft_timestamp", System.currentTimeMillis())
.apply()
// Pause video
binding?.videoPlayer?.pause()
// Release exclusive resources
releaseCamera()
releaseAudioFocus()
}
override fun onResume() {
super.onResume()
// Restore draft
binding?.titleInput?.setText(prefs.getString("draft_title", ""))
binding?.bodyInput?.setText(prefs.getString("draft_body", ""))
acquireCamera()
acquireAudioFocus()
}
}
The NoteEditorActivity example demonstrates proper onPause handling: saving a draft to SharedPreferences via apply(), pausing a video file, releasing the camera and audio focus. Each call is lightweight and fast, without blocking the UI thread long enough to trigger ANR. Note the order: super.onPause() is called on the first line — this guarantees that system logic executes even if an exception occurs in the user code.
onPause is the last point where the developer can reliably save user data before the app is hidden or killed by the system. After onStop, the system may terminate the process if memory is low, without calling onDestroy. The onSaveInstanceState() method is called after onPause, but its Bundle is not intended for long-term storage — it only lives until the next onCreate.
SharedPreferences with asynchronous apply() is the optimal way to save small amounts of data in onPause. Unlike commit(), which synchronously writes data to disk and returns a boolean, apply() immediately saves data in memory and schedules an asynchronous disk write. This takes less than 1 millisecond on the UI thread compared to 10–100 milliseconds for commit().
override fun onPause() {
super.onPause()
// ❌ Bad: synchronous write blocks the thread
// prefs.edit().putInt("score", score).commit()
// ✅ Good: asynchronous write
prefs.edit().putInt("score", score).apply()
// For complex objects — caching in ViewModel
viewModel.saveState()
}
For structured data (SQLite via Room) in onPause, use coroutines with lifecycleScope. ViewModelScope automatically cancels the coroutine when the ViewModel is destroyed, preventing writes to a closed database. Writing through Room with coroutines takes 5–15 milliseconds and does not block the UI thread.
// 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 is called when the Fragment ceases to be active but may remain visible. This happens when: a Fragment is replaced by another Fragment via FragmentTransaction; a Fragment is no longer the current page in a ViewPager; the Activity containing the Fragment receives onPause. The interaction between Activity onPause and Fragment onPause is strictly hierarchical: the Activity receives onPause first, then all its Fragments.
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()
}
}
}
Specifics of working with maps in onPause: Google Maps and Yandex Maps consume significant GPU resources in active follow mode. When focus is lost, it makes sense to disable map animation and reduce marker update frequency, and upon regaining focus, restore full functionality. This improves performance and reduces power consumption when switching between screens.
One of the most common confusions among beginner Android developers is not understanding the difference between onPause and onStop. Let us examine each scenario and determine the correct method.
| Scenario | onPause | onStop |
|---|---|---|
| Opening a dialog window | Called | Not called |
| Opening a new Activity (non-transparent) | Called | Called |
| Pressing the Home button | Called | Called |
| Screen lock | Called | Called |
| Incoming call | Called | Called |
| Transparent Activity on top | Called | Not called |
| Split Screen (half screen) | Called | Not called |
| PiP (Picture-in-Picture) | Called | Not called |
The main rule: onPause is called on any loss of focus, onStop is only called when visibility is completely lost. If the Activity remains visible (even partially), onStop is not called. This is critically important for Split Screen, PiP, and transparent Activity modes — here onPause/onResume work, but onStart/onStop do not.
onPause is the most time-critical lifecycle method because it blocks the rendering of the next Activity. The system waits for the current Activity’s onPause to complete before showing the new one. If onPause takes longer than 100 milliseconds, the user notices a transition delay; if longer than 5 seconds, the system displays an ANR.
The Google Android Performance Guide (2025) offers the following recommendations for onPause: do not perform network requests — they should be cancelled or moved to WorkManager; do not write large files to disk — use BufferedWriter on a background thread; do not execute complex SQL queries — Room operations should be asynchronous via coroutines; avoid creating new objects — garbage collection in onPause exacerbates the delay; use apply() instead of commit() for SharedPreferences.
override fun onPause() {
super.onPause()
// ❌ Bad: HTTP request blocks UI
// val response = api.syncSave(data).execute()
// ❌ Bad: synchronous file write
// FileOutputStream(file).write(data)
// ✅ Good: asynchronous save
lifecycleScope.launch {
withContext(Dispatchers.IO) {
api.saveData(data)
fileDao.write(data)
}
}
// ✅ Good: lightweight SharedPreferences write
prefs.edit().putString("key", value).apply()
}
Profiling onPause via Android Studio Profiler (CPU trace) shows the exact execution time. If onPause takes more than 100 ms, Profiler highlights the method in yellow, and more than 500 ms in red. In commercial projects at IT Sectr, we use Macrobenchmark tests that automatically check the transition time between Activities and signal performance regressions in the CI pipeline.
Even experienced developers make mistakes in onPause. Let us examine five typical problems and their solutions.
Calling Room DAO with a synchronous query (.executeAsObservable() without coroutines) in onPause blocks the UI thread for 10–50 ms. If GC or write contention occurs at the same time, the delay can reach 200–500 ms. Solution: use coroutines with Dispatchers.IO or apply() for SharedPreferences.
onPause is not the place to register listeners. If you register a BroadcastReceiver in onPause, it remains active when the Activity is no longer visible. Registration should only happen in onStart/onResume, and in onPause/onStop — only unregistration. The exception is Intent-driven APIs that require registration before the call.
If an unhandled exception occurs in onPause, the system does not call onStop and onDestroy. The Activity stalls in an undefined state, and onResume upon return may not properly restore released resources. Solution: wrap critical operations in try/catch with logging via Log.e().
There is no need to save data in onPause that can be easily restored. For example, API response results should be cached in Room or DataStore at the moment of retrieval, not in onPause. Save only what the user entered manually and cannot be restored automatically — text in fields, selected items, scroll position.
super.onPause() should be called, but unlike onCreate, omitting it does not cause an immediate crash. The system “forgives” the missing super in onPause, but the internal state machine enters an incorrect state. The next onResume call may fail to restore input focus, leaving the Activity “frozen.” Always call super.onPause() as early as possible.
Frequently Asked Questions
Calling finish() in onPause will terminate the Activity immediately after returning from the method. This is a valid scenario if the screen needs to be closed upon losing focus (for example, an authorization screen when the app is minimized). However, finish() triggers the full termination cycle: onStop onDestroy, which adds a delay to the transition. Use finish() in onPause only when it is truly necessary.
onPause is for saving data that should survive process termination (drafts in SharedPreferences/Room). onSaveInstanceState is for saving temporary UI state that is only needed until the next onCreate (scroll position, selected tab). The onSaveInstanceState Bundle is not preserved when the app is fully terminated — it only exists in memory. onPause data is saved to disk and survives a reboot.
Not recommended. Opening a dialog or popup in onPause leads to a WindowLeakException if the Activity has already been finished. If you need to show a notification upon losing focus, use NotificationManager (system notifications) — this is safe and expected by the user. For deferred actions, use AlarmManager or WorkManager.
onPause is guaranteed to be called before the Activity ceases to be active. onStop may not be called if the system kills the process to free memory — in this case, onDestroy is also not called. onPause is the only method after onResume that is always called, regardless of the reason for losing focus. Therefore, all critical data is saved precisely in onPause.
Robolectric or FragmentScenario from AndroidX Test are used for testing onPause. FragmentScenario.create() moveToState(State.STARTED) moveToState(State.RESUMED) moveToState(State.STARTED) sequentially triggers onPause. Then you verify that data was saved in SharedPreferences or that the camera was released via a mock object. Robolectric 4.12+ supports onPause/onResume emulation without a physical device.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also