onPause: What It Is, Saving Activity State in Android

Author: IT Sectr Published: 2026-03-04 Reading time: 10 min

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 — Activity loses focus but remains visible; the last guaranteed point for saving data
  • Saving State — critical user data is saved in onPause: drafts, form text, progress
  • Releasing Resources — camera, microphone, video player are released in onPause for transfer to another app
  • Time Limit — onPause must complete within 100 ms; exceeding this causes ANR and delays the transition
  • SharedPreferences.apply() — asynchronous write in onPause; commit() blocks the thread and can cause ANR
  • onPause vs onStop — onPause when partially visible (dialog), onStop when fully hidden (another Activity)
  • onSaveInstanceState — called after onPause to save temporary state in a Bundle

What is onPause in Android

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().

onPause in Activity

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).

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()

        // 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.

Saving State in onPause

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 apply()

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().

kotlin
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()
}

Room and Coroutines

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.

kotlin
// 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

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.

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()
        }
    }
}

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.

onPause vs onStop: Difference and Scenarios

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.

ScenarioonPauseonStop
Opening a dialog windowCalledNot called
Opening a new Activity (non-transparent)CalledCalled
Pressing the Home buttonCalledCalled
Screen lockCalledCalled
Incoming callCalledCalled
Transparent Activity on topCalledNot called
Split Screen (half screen)CalledNot called
PiP (Picture-in-Picture)CalledNot 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 Timing and Performance

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.

Performance Recommendations

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.

kotlin
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.

Common Mistakes in onPause

Even experienced developers make mistakes in onPause. Let us examine five typical problems and their solutions.

Synchronous Database Write

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.

Registering New Listeners

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.

Ignoring Exceptions

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().

Saving Redundant Data

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.

Forgot super.onPause()

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

What happens if you call finish() in onPause?

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.

How is onPause different from onSaveInstanceState?

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.

Can I open a dialog in onPause?

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.

Why is onPause a guaranteed save point, but onStop is not?

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.

How to test onPause in unit tests?

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

  • onPause — Activity loses input focus but remains partially visible; the last guaranteed point for saving data
  • Saving — SharedPreferences.apply() or Room via coroutines; commit() and synchronous operations are prohibited
  • Resource Release — camera, audio focus, video player are released in onPause for transfer to another app
  • 100 ms Limit — onPause blocks rendering of the next Activity; exceeding the limit causes ANR
  • onPause vs onStop — onPause on focus loss (visibility preserved), onStop on full concealment
  • Fragment.onPause — hierarchical call after Activity.onPause; specifics for maps and ViewPager
  • Common Mistakes — synchronous write, registering listeners, ignoring try/catch, redundant saving
  • super.onPause() — call as early as possible; omission does not crash but breaks the state machine

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.

Discuss the project

Read also