onStop — a method of the Activity lifecycle in Android, called by the system when the Activity is no longer visible to the user. The Activity transitions to the Stopped state after a new Activity completely covers it, or when the app is minimized. In the onStop method, the developer must stop animations, release camera and sensor resources, and save drafts of entered data. According to Android Vitals (Google, 2025), proper onStop handling reduces the number of ANRs (Application Not Responding) when minimizing the app by 35%. After onStop, the system may call onRestart (return to screen) or onDestroy (complete termination). Android Developers Documentation on the Activity Lifecycle describes onStop as the boundary between visible and invisible states.
Key Takeaways
onStop — a callback method of the AppCompatActivity class (and its predecessor Activity), called by the Android operating system when the Activity is no longer fully visible to the user. At this point, the Activity is hidden by another Activity, a dialog window, the system launcher, or the lock screen. From the lifecycle perspective, onStop follows onPause and signals that the Activity is no longer visible on screen, although the Activity object and its state remain in memory.
When the Activity transitions to the Stopped state, it retains its state in RAM — all fields, View hierarchy, and ViewModel remain accessible. This distinguishes Stopped from the Destroyed state, where the Activity is completely removed. The system UI may kill the app process in Stopped state when memory is low — this is the so-called process death. The developer must save critical data (drafts, scroll position) in onSaveInstanceState(), which is called before onStop, to guarantee restoration upon process death.
According to the Android Compatibility Definition Document (CDD) for version 14+, a process in Stopped state has a reduced priority for OOM Killer killing — lower than processes in the Background phase, but higher than cached processes. According to Google statistics, 68% of process death cases occur when the Activity is in Stopped state, not Paused.
onStop is called when the Activity completely loses visibility, regardless of the reason: launching a new Activity on top, minimizing the app (pressing Home), locking the screen, an incoming call, or opening a system dialog. In all these cases, the Activity first receives onPause (partial loss of focus), then onStop (complete loss of visibility).
Main scenarios for onStop invocation:
It is important to understand that onStop is not called on screen rotation — in this case, the Activity is destroyed (onPause → onStop → onDestroy) and recreated (onCreate → onStart → onResume). The exception is the android:configChanges="orientation" flag in the manifest, which prevents Activity recreation and instead calls onConfigurationChanged().
onStop occupies a central place in the Activity lifecycle sequence between visible and invisible states. The complete sequence: onCreate → onStart → onResume → (active state) → onPause → onStop → onDestroy (or onRestart → onStart → onResume upon return).
| State | Method | Visibility | Interaction | Memory |
|---|---|---|---|---|
| Created | onCreate | No | No | Allocated |
| Started | onStart | Partial | No | Full |
| Resumed | onResume | Full | Yes | Full |
| Paused | onPause | Partial | No | Full |
| Stopped | onStop | No | No | Full* |
| Destroyed | onDestroy | No | No | Freed |
*In the Stopped state, the Activity is kept in memory but may be killed by the system under low memory conditions. The priority of Stopped process killing is second-to-last, above only cached empty processes.
onStop and onSaveInstanceState: The system calls onSaveInstanceState(Bundle) before onStop to save dynamic UI state. The developer overrides this method to save input field values, RecyclerView position, and selected items into the Bundle. Even if the Activity is not destroyed (the user simply minimized and returned), the Bundle is passed to onCreate upon configuration changes. Google recommends saving only transient UI state — not repository data or ViewModel, which live outside the Activity.
In onStop, the developer must release all resources that are not needed when the Activity is not visible. This reduces battery, CPU, and memory load, and also prevents ANRs when returning to the activity.
What to release in onStop:
What not to do in onStop: Do not perform long-running operations — saving large data to the database, network requests, complex computations. onStop runs on the main thread and blocks the return to the Activity. For long-running operations, use WorkManager with a delay or coroutines in viewModelScope. Do not release ViewModel resources — ViewModel survives onStop and will be used upon return.
onPause and onStop differ in the degree of visibility loss and the scope of mandatory actions. onPause is called upon partial loss of focus (e.g., opening a dialog window or system menu), onStop — upon complete loss of visibility. This distinction is important for choosing which resources to release at each stage.
| Characteristic | onPause | onStop |
|---|---|---|
| Visibility level | Partially visible | Completely invisible |
| Focus | Lost | Lost |
| Execution time | Up to 500 ms | Up to 5 s (ANR timeout) |
| Resources to release | Critical (media, camera) | All invisible (sensors, animations, location) |
| Restoration | onResume | onRestart → onStart → onResume |
| Process priority | High (Foreground) | Medium (Background) |
General rule: in onPause, release system resources that immediately affect the user experience of another app (camera, media player); in onStop — all other resources not needed when the Activity is hidden. Google recommends saving critical user data (email draft, settings) in onPause, as onStop may not be called during fast switching.
When the user returns to a hidden Activity, the system calls onRestart → onStart → onResume. The onRestart method signals that the Activity is returning from the Stopped state. This is an important stage for restoring UI and resources that were released in onStop.
Call sequence upon return:
If the app process was killed by the system in Stopped state, onCreate is called instead of onRestart, and the Bundle from onSaveInstanceState is passed for state restoration. This scenario (process death) is one of the most common causes of bugs in Android apps: developers implement onRestart but forget to account for restoration through onCreate after process death.
Demonstrates correct sensor unsubscription and animation stopping when hiding the Activity. Upon returning to the screen, resources are restored in onStart.
class MainActivity : AppCompatActivity() {
private lateinit var sensorManager: SensorManager
private var accelerometer: Sensor? = null
private var rotationAnimator: ObjectAnimator? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
}
override fun onStart() {
super.onStart()
accelerometer?.let {
sensorManager.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_NORMAL)
}
rotationAnimator = ObjectAnimator.ofFloat(findViewById(R.id.icon), "rotation", 0f, 360f)
rotationAnimator?.apply {
duration = 3000
repeatMode = ValueAnimator.RESTART
repeatCount = ValueAnimator.INFINITE
start()
}
}
override fun onStop() {
super.onStop()
sensorManager.unregisterListener(sensorListener)
rotationAnimator?.cancel()
}
override fun onRestart() {
super.onRestart()
Log.d("MainActivity", "Activity returns from Stopped state")
}
private val sensorListener = SensorEventListener { event, _ ->
Log.d("MainActivity", "Accel: x=${event.values[0]}, y=${event.values[1]}, z=${event.values[2]}")
}
}
The code registers the accelerometer sensor and starts an infinite rotation animation in onStart. In onStop, the sensor is unregistered and the animation is canceled — this prevents battery drain when the Activity is hidden. After returning via onRestart → onStart, resources are recreated.
A modern approach using ViewModel + SavedStateHandle. Form data is automatically saved during onStop without manual Bundle handling.
class FormViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
var email: String
get() = savedStateHandle["email"] ?: ""
set(value) { savedStateHandle["email"] = value }
var message: String
get() = savedStateHandle["message"] ?: ""
set(value) { savedStateHandle["message"] = value }
}
class FormActivity : AppCompatActivity() {
private val viewModel: FormViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_form)
Log.d("FormActivity", "onCreate: email=${viewModel.email}")
}
override fun onStop() {
super.onStop()
Log.d("FormActivity", "onStop: data saved in SavedStateHandle")
}
}
SavedStateHandle automatically saves values to the Bundle during onSaveInstanceState, which is called before onStop. On screen rotation or process death, data is restored without loss. Google recommends SavedStateHandle for forms and drafts instead of direct onSaveInstanceState.
Using lifecycleScope with coroutines for asynchronous data saving during onStop transition. The coroutine runs on the IO dispatcher without blocking the main thread.
class NoteActivity : AppCompatActivity() {
private val noteRepository = NoteRepository()
override fun onStop() {
lifecycleScope.launch(Dispatchers.IO) {
val text = findViewById<EditText>(R.id.note_content).text.toString()
noteRepository.saveDraft(text)
withContext(Dispatchers.Main) {
Log.d("NoteActivity", "Draft saved in onStop")
}
}
super.onStop()
}
}
The lifecycleScope.launch coroutine is automatically canceled if the Activity lifecycle ends. Using Dispatchers.IO ensures that database or file writes do not block the return to the Activity. According to Google, coroutines in lifecycleScope are the preferred way to perform asynchronous operations in onStop.
Frequently Asked Questions
onStop — the Activity is no longer visible but remains in memory in the Stopped state. The system can return the Activity via onRestart. onDestroy — the Activity is destroyed, memory is freed. After onDestroy, return is only possible by creating a new Activity instance (onCreate).
Yes, it is mandatory. super.onStop() ensures proper operation of system components: fragments, LoaderManager, ViewModelStore. Skipping super.onStop() can cause memory leaks and incorrect fragment restoration. Always call super.onStop() either last or first — the order is not critical, but the call is mandatory.
Use Log.d or Timber in each lifecycle method. Enable logcat filtering by your Activity tag. For production, use Android Vitals — Google automatically collects lifecycle metrics and shows anomalies in Play Console. Lifecycle monitoring is also available through ProcessLifecycleOwner.
An uncaught exception in onStop causes a Force Close of the app. The system does not catch exceptions in lifecycle callbacks. If onStop performs operations that may throw exceptions (file operations, network), wrap them in try-catch and log the error without interrupting super.onStop().
No, the Bitmap in the Activity will be collected by GC if there are no references to it. Forced release (recycle()) in onStop is not required and is even harmful — if the Activity returns via onRestart, the Bitmap would have to be loaded again. Use Glide or Coil for image loading — these libraries automatically manage caching and lifecycle.
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