onStart is an Android lifecycle method that is called when an Activity or Fragment becomes visible to the user. At this moment, the screen appears on the device display but cannot yet interact with the user — input focus is absent until onResume is called. The onStart method is ideal for registering system listeners, connecting to geolocation services, and launching animations that should run while the component is visible on screen. Learn more about the full Activity lifecycle in the article Activity Lifecycle.
Key Takeaways
onStart is the second method of the Activity lifecycle, called by the system after onCreate (or after onRestart when returning from a stopped state). At the moment onStart is called, the Activity or Fragment becomes visible on screen. The user sees the interface, but the screen is not yet ready for interaction — input focus will appear only after onResume.
The onStart method is part of the “visible lifetime” of an Activity — the interval between onStart and onStop. During this period, the Activity may be partially covered by other windows (e.g., a transparent Activity or dialog window), but its UI remains visible. This distinguishes the visible lifetime from the “foreground lifetime” (onResume — onPause), when the Activity has full input focus.
Understanding this three-level hierarchy is critical for properly distributing code. onCreate — one-time initialization, onStart — connecting visible resources, onResume — exclusive access to exclusive resources. A developer who confuses these levels risks creating memory leaks or incorrect application behavior when switching between screens.
In Activity, the onStart method is called every time the screen appears on the display — both on first launch (after onCreate) and when returning from background (after onRestart). Unlike onCreate, onStart can be called multiple times during the life of an Activity instance, so code that should execute every time the screen appears is placed here.
class DashboardActivity : AppCompatActivity() {
private val connectivityReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val isConnected = ... // ConnectivityManager check
binding?.statusIndicator?.setColor(
if (isConnected) Color.GREEN else Color.RED
)
}
}
override fun onStart() {
super.onStart()
registerReceiver(
connectivityReceiver,
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
)
SensorManager.getInstance().registerStepCounter()
}
override fun onStop() {
unregisterReceiver(connectivityReceiver)
SensorManager.getInstance().unregisterStepCounter()
super.onStop()
}
}
Key rule: all resources connected in onStart must be released in onStop. This ensures that when the Activity is hidden from the screen, it does not consume battery, listen to system events, or occupy memory. Android Studio includes lint rules that warn about registering a BroadcastReceiver without corresponding unregistration.
onStart in Fragment is closely tied to the lifecycle of the host Activity. The Fragment receives the onStart call after its containing Activity has received onStart. However, if the Fragment is added in deferred mode (FragmentTransaction.commit() without addToBackStack), onStart may be called with a delay.
class MapFragment : Fragment() {
private var mapView: MapView? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
mapView = MapView(requireContext())
return mapView!!
}
override fun onStart() {
super.onStart()
mapView?.onStart()
LocationService.connect(requireContext())
}
override fun onStop() {
mapView?.onStop()
LocationService.disconnect()
super.onStop()
}
}
Fragment.onStart specifics: if the Fragment is in a ViewPager with offscreenPageLimit = 1, neighboring fragments will also receive onStart before becoming visible. This can lead to premature listener registration. For such cases, use the setUserVisibleHint() method or check isVisible inside onStart to register listeners only for actually visible fragments.
The main difference between onStart and onResume is the level of screen activity. onStart signals that the Activity is visible on screen but not necessarily in the foreground. onResume signals that the Activity is in the foreground and has input focus. The difference is demonstrated by a dialog window example: when a Dialog appears over an Activity, the Activity loses onResume (onPause is called) but remains visible — onStart/onStop are not called.
The comparison table clearly shows in which scenarios each method is called:
| Scenario | onStart | onResume |
|---|---|---|
| App launch | Called | Called |
| Dialog opened over Activity | Not called | onPause (loses focus) |
| Home button pressed | onStop (hidden) | onPause → onStop |
| Return from Recents | onStart (visible) | onResume (focus) |
| Screen rotation | onCreate → onStart | → onResume |
| Incoming call | onStop (hidden) | onPause → onStop |
This table helps the developer decide which method to place specific code into. For example, if the app should pause video playback during any screen overlap (even a dialog), the code goes in onPause. If the video should only stop when the screen is completely hidden, the code goes in onStop.
onStart is the optimal place to register listeners that should only work while the Activity is visible on screen. This concerns three main types of system components: BroadcastReceiver for system events, LocationListener for geolocation, and SensorListener for device sensors.
BroadcastReceiver is dynamically registered via Context.registerReceiver() in onStart and unregistered in onStop via unregisterReceiver(). Dynamic registration is preferable to static registration (in the manifest) because it limits the receiver’s lifetime to the Activity’s visible period — the app does not wake up from system broadcast messages when the Activity is hidden.
private val batteryReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
binding?.batteryText?.text = "$level%"
}
}
override fun onStart() {
super.onStart()
registerReceiver(batteryReceiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
}
override fun onStop() {
unregisterReceiver(batteryReceiver)
super.onStop()
}
Geolocation and sensors are resource-intensive operations. Requesting GPS updates in onStart and canceling in onStop ensures that the app does not drain battery when the screen is hidden. For fine-tuning, use requestLocationUpdates with a minimum interval and distance — for example, 10 seconds and 10 meters, which provides an optimal balance between accuracy and power consumption.
Starting animations in onStart, rather than in onCreate, ensures that the animation starts every time the screen appears. If you start an animation in onCreate, it will only work on the first Activity creation, not when returning from background. onStart is called every time the Activity becomes visible, making it the ideal place to start cyclic animations and transitions.
private lateinit var pulseAnimator: ValueAnimator
override fun onStart() {
super.onStart()
pulseAnimator.start()
binding?.loadingIndicator?.animate()?.alpha(1f)?.start()
}
override fun onStop() {
pulseAnimator.cancel()
binding?.loadingIndicator?.animate()?.cancel()
super.onStop()
}
For animations using ObjectAnimator or ValueAnimator, it is important to call cancel() in onStop. If the animation continues running after the Activity is hidden, it uselessly consumes GPU and CPU resources, degrading device performance and accelerating battery drain. Android Studio Profiler (GPU graph) allows you to track active animations and detect leaks.
The onStart/onStop pairing rule also applies to working with the camera for preview (CameraX). Opening the camera in onStart and closing it in onStop ensures that the camera is not blocked for other apps when your app is not visible on screen. Violating this rule is a common cause of negative reviews on Google Play.
Frequently Asked Questions
onStart — for listeners that should work while the screen is visible (BroadcastReceiver, LocationListener, SensorListener). onResume — for resources requiring exclusive access (camera, video capture, speech recognition). System event listeners do not require exclusive access and can work with partial overlap — they are registered in onStart. The camera should only be active with full focus — it is opened in onResume.
onStart is always called if the Activity transitions to a visible state. The only scenario without onStart — the Activity is created and immediately finishes (e.g., due to an error in onCreate). In this case, onDestroy is called right after onCreate. But this is an emergency scenario that should not occur in properly written code.
Yes, onStart may not receive onResume if another Activity or a transparent window opens immediately over the Activity. For example, if an authorization screen is launched after onCreate (Activity A → Activity B), in Activity A onStart is called, but onResume is not — it immediately receives onPause → onStop when overlapped by screen B.
onStart can be called multiple times during the life of an Activity instance. Every time the Activity transitions from a hidden state (onStop) to a visible state, onStart is called. In practice, with active app usage, onStart can be called dozens or hundreds of times per session.
Loading data in onStart is justified if the data should be updated every time the screen appears. For example, a news feed or notification list. However, loading should be asynchronous — via coroutines with lifecycleScope, to avoid blocking the UI thread. For data that does not change between screen appearances, loading once in onCreate is sufficient.
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