Inactive — a transitional state in the application lifecycle between Active and Background, where the app is visible on screen but does not receive touch events. We explain how Inactive occurs on iOS and Android, which delegate methods handle it, and how to properly process interruptions — calls, notifications, and system gestures.
Key Takeaways
Inactive is an intermediate state in the mobile app lifecycle that occurs during the transition between Active and Background. In this state, the app is still in the foreground and visible to the user, but does not receive touch events, key presses, or other UI events. The system blocks event delivery to the app, but the UI remains on screen and does not minimize.
The nature of Inactive is temporary. This state lasts exactly as long as the system interruption lasts: from 0.1 seconds when quickly closing Control Center to several seconds during an incoming call with the call screen. After the interruption ends, the app either returns to Active or transitions to Background if the user switched to another app. Inactive is the only state that can transition in both directions: back to Active or further to Background.
On iOS, Inactive is managed automatically by the system. The developer cannot extend or shorten the time spent in Inactive — it is fully controlled by UIApplication. The only thing the developer can do is properly handle the transition to Inactive via applicationWillResignActive and the return via applicationDidBecomeActive. On Android, the equivalent is onPause, although the semantics differ: onPause is called even when an Activity is partially covered by another component.
On iOS, Inactive is a separate application lifecycle state (one of five: Not Running, Active, Inactive, Background, Suspended). On Android, there is no direct equivalent — onPause signals that the Activity is losing input focus but may remain visible (for example, when a dialog opens). The key difference: iOS Inactive is an app-wide state, while Android onPause is a per-Activity state. In Android multi-window, one Activity can be in onPause (without focus) while another is in onResume (with focus).
| Characteristic | iOS Inactive | Android onPause |
|---|---|---|
| UI visible | Yes | Yes (partially or fully) |
| Touch events | Does not receive | Does not receive |
| Duration | Until interruption ends | Until focus returns or goes to background |
| Next state | Active or Background | onResume or onStop |
| Level | App (UIApplication) | Activity |
| Multi-window | One scene active | Multiple Activities in onPause |
Inactive on iOS occurs in several strictly defined scenarios. The user opens Control Center (swipe down from the top-right corner on iPhone X+ or swipe up on older models). The user opens Notification Center (swipe down from the top-left corner). An incoming call arrives — the system shows the call screen over the app. A system permission is requested — geolocation, microphone, camera, contacts. On iPad, Slide Over or Split View is launched — the active scene becomes Inactive.
On Android, onPause (the equivalent of Inactive) occurs in an even wider range of situations. Opening a dialog (AlertDialog, DialogFragment). Partial overlay of an Activity by another Activity (for example, a transparent Activity for authentication). Screen rotation (the Activity is recreated, sequence: onPause → onStop → onDestroy → onCreate → onStart → onResume). Multi-window mode — the inactive window receives onPause. Each of these events requires suspending resource-intensive operations to preserve battery and performance.
import UIKit
extension Notification.Name {
static let systemInterruptionBegan = Notification.Name("systemInterruptionBegan")
static let systemInterruptionEnded = Notification.Name("systemInterruptionEnded")
}
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillResignActive(_ application: UIApplication) {
// App transitions to Inactive — system interruption
print("Interruption: Control Center, call, or system alert")
// Pausing time-sensitive operations
pauseVideoPlayback()
stopContinuousDataCollection()
hideSensitiveInformation()
// Notifying components
NotificationCenter.default.post(name: .systemInterruptionBegan, object: nil)
}
// Return from Inactive to Active
func applicationDidBecomeActive(_ application: UIApplication) {
resumeVideoPlayback()
restartDataCollection()
NotificationCenter.default.post(name: .systemInterruptionEnded, object: nil)
}
private func pauseVideoPlayback() {
// Pausing video to prevent audio overlap
}
private func hideSensitiveInformation() {
// Hiding sensitive data on screen screenshot
// Control Center/App Switcher takes a UI screenshot
}
}The code shows Inactive handling in UIKit. applicationWillResignActive pauses video, stops data collection, and hides sensitive information. This is important because when Control Center or App Switcher is opened, the system takes a screenshot of the current UI — the user could see confidential data in the preview. NotificationCenter allows app components to subscribe to interruption events.
On iOS, Inactive is handled by a pair of methods: applicationWillResignActive (transition to Inactive) and applicationDidBecomeActive (return from Inactive). These methods are part of UIApplicationDelegate and are called for every transition through Inactive. Since iOS 13 and UISceneDelegate, sceneWillResignActive and sceneDidBecomeActive have been added for multi-window scenarios.
On iPad with iOS 13+, an app can have multiple scenes (windows). Each scene has its own lifecycle. One scene can become Inactive (the user switched to another scene) while another remains Active. This is an important difference from iPhone, where Inactive is a global state for the entire app. When developing for iPad, you need to handle Inactive for each scene separately.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
// Scene becomes inactive
func sceneWillResignActive(_ scene: UIScene) {
// On iPad this scene loses focus, but others may remain active
print("Scene loses activity")
// Pausing this scene's tasks
pauseSceneSpecificOperations()
}
// Scene becomes active
func sceneDidBecomeActive(_ scene: UIScene) {
print("Scene became active")
resumeSceneSpecificOperations()
}
private func pauseSceneSpecificOperations() {
// Pausing operations specific to this scene
}
private func resumeSceneSpecificOperations() {
// Resuming operations when focus returns
}
}
// AppDelegate remains the entry point, delegates to scenes
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
return UISceneConfiguration(
name: "Default Configuration",
sessionRole: connectingSceneSession.role
)
}
}The code shows a SceneDelegate for handling Inactive at the scene level. sceneWillResignActive is called when a specific window loses focus — this can happen when switching between windows on iPad. AppDelegate configures UISceneConfiguration to support multi-window. Each scene has an independent state, and the developer must handle them separately.
On Android, the direct equivalent of iOS Inactive is the onPause() method of the Activity lifecycle. It is called when the Activity loses input focus but may remain visible. Typical scenarios: opening a dialog, launching another Activity in the same app, an incoming call, pressing the Home or Recents button. In onPause, the developer should suspend resource-intensive operations — animations, video playback, camera work.
An important Android distinction is that onPause always precedes onStop, but not vice versa. An Activity can receive onPause without onStop (for example, when opening a transparent Activity). Also, onPause can be called multiple times during an Activity's lifetime — on each focus switch. Do not place one-time logic in onPause — use onStop for final operations and onPause only for suspending interactive actions.
class VideoPlayerActivity : AppCompatActivity() {
private var exoPlayer: ExoPlayer? = null
private var currentPosition: Long = 0L
override fun onPause() {
super.onPause()
// App loses focus — pausing video
exoPlayer?.let { player ->
if (player.isPlaying) {
currentPosition = player.currentPosition
player.pause()
}
}
// Hiding sensitive data (GDPR/banking screens)
if (window.decorView.systemUiVisibility and
View.SYSTEM_UI_FLAG_SECURE == 0
) {
hideSensitiveOverlay()
}
}
override fun onResume() {
super.onResume()
// Focus returns — resuming playback
exoPlayer?.seekTo(currentPosition)
exoPlayer?.play()
showSensitiveOverlay()
}
private fun hideSensitiveOverlay() {
// Overlaying a black screen on financial data
}
}The code shows proper onPause handling for a video player. ExoPlayer is paused when focus is lost, and the playback position is saved. On return to onResume, the player resumes playback from the saved position. Additionally, a pattern for hiding sensitive data is shown — important for financial and medical apps that require protection from screenshots when switching.
First rule — hide confidential data when transitioning to Inactive. When the user opens Control Center or App Switcher, iOS takes a screenshot of the current screen. On Android, similarly, the system shows a preview of the last Activity in Recents. Use UIApplication.shouldSnapshotSecureApp (iOS 16+) or FLAG_SECURE (Android) to protect confidential screens.
Second rule — pause animations and media. Inactive is not a good time for playing video or animations, since the user cannot see them. Moreover, background playback can cause audio to overlap with system sounds (ringtone, notification). Stop AVPlayer, ExoPlayer, and UIView.animate when going to Inactive and resume when returning to Active.
Third rule — block data input. If the app contains input forms or drafts, lock the keyboard and input fields when going to Inactive. This prevents accidental input on return and protects against data interception through system overlays. On iOS, resign the first responder (view.endEditing(true)), on Android — clear focus (currentFocus?.clearFocus()).
Fourth rule — do not perform long operations in applicationWillResignActive or onPause. These methods should complete in fractions of a second. If you need to save a large amount of data, start saving on a background thread and complete it in applicationDidEnterBackground or onStop. iOS gives 5 seconds for applicationWillResignActive to execute, after which the system may force-terminate the app.
import UIKit
final class SecureOverlayManager {
private var blurView: UIVisualEffectView?
func showBlurOverlay() {
guard let window = UIApplication.shared.keyWindow,
blurView == nil
else { return }
let blur = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
blur.frame = window.bounds
blur.autoresizingMask = [.flexibleWidth, .flexibleHeight]
window.addSubview(blur)
blurView = blur
}
func removeBlurOverlay() {
blurView?.removeFromSuperview()
blurView = nil
}
}
// Usage in AppDelegate
func applicationWillResignActive(_ application: UIApplication) {
SecureOverlayManager().showBlurOverlay()
}
func applicationDidBecomeActive(_ application: UIApplication) {
SecureOverlayManager().removeBlurOverlay()
}The code shows the implementation of a safe overlay for data protection during transition to Inactive. A UIVisualEffectView with blur effect is overlaid on top of the entire UI when going to Inactive and removed when returning to Active. This ensures that confidential data will not be visible in App Switcher and Control Center screenshots. Similarly, you can use UIImageView with a logo for a branded overlay.
Frequently Asked Questions
Yes. Inactive is a mandatory intermediate state before transitioning to Background on iOS. An app cannot go from Active directly to Background — it first becomes Inactive, then Background. On Android, similarly, onPause is always called before onStop. This gives the developer an opportunity to prepare data for saving before fully going to the background.
Yes. On iPad, when launching Slide Over or Split View, the active scene becomes Inactive, even though no system interruption occurs — the user is simply interacting with another scene. This is a multi-window iPadOS feature. On iPhone, Inactive is always triggered by a system interruption — call, notification, Control Center, or Notification Center.
Typically from 0.1 to 2 seconds. During an incoming call with the call screen — up to 30 seconds (until the user answers or declines the call). iOS does not forcibly limit time in Inactive, but the system may terminate the app if it does not respond to events (watchdog). On Android, onPause has no time limit, but it is recommended to complete work within 200 ms.
ScenePhase.inactive — the ScenePhase enum value set when the scene is in the foreground but not receiving events. In SwiftUI, you can observe it through @Environment(\.scenePhase) and react via onChange. When transitioning from .active to .inactive, pause timers and animations. When returning to .active, resume them. When going to .background, save state.
No, only for apps that handle confidential data: banking, medical, corporate, and messaging apps with private chats. For games and entertainment apps, hiding UI is not required. However, pausing gameplay and sound during Inactive is good practice to avoid audio overlapping with system notifications. Apple recommends hiding sensitive data but does not require it.
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