Background and Foreground
What happens to an app when you leave it, why the OS kills it, and what must survive. Learn the app lifecycle on iOS and Android, how to test background and restore scenarios, and hunt bugs in a banking app.
Daniel is booking a train ticket. Halfway through the passenger form, he switches to his email to copy a booking code. He replies to a message, checks a map, takes a photo. Ten minutes later he goes back to the train app, and it opens on the home screen. The form is empty. The seat he picked is gone. He books with a competitor instead.
On the developer’s brand-new phone with nothing else running, the app always came back perfectly. On Daniel’s three-year-old phone, the OS had quietly killed it to free memory. Nobody had tested that.
Why it matters
People don’t use apps in one long session. They jump between apps dozens of times an hour. Every time they leave, your app moves to the background, and from that moment the OS decides what happens to it: keep it, freeze it, or kill it.
Background and foreground bugs are some of the most common mobile bugs because:
- Developers rarely see them. Fast test phones with lots of memory almost never kill apps.
- They depend on time. “Come back after 5 seconds” and “come back after 2 hours” are completely different tests.
- They touch privacy and security: what’s visible in the app switcher, and whether an expired session is handled.
The app lifecycle
The app lifecycleApp lifecycleThe states an app moves through: not running, foreground, background, suspended and terminated.Open in glossary → is the set of states an app moves through. You don’t need to know the code, but you do need to know the states, because each one is a test idea.
| State | Visible? | Running code? | Example |
|---|---|---|---|
| Not running | No | No | Never opened since the phone restarted |
| Foreground, active | Yes | Yes | You’re scrolling the app |
| Foreground, inactive | Yes (partly) | Yes, but gets no touches | App switcher open, Control Center pulled down, an incoming call screen on top |
| Background | No | Briefly | You just pressed Home |
| Suspended | No | No, frozen in memory | A few seconds after leaving |
| Terminated | No | No, removed from memory | The OS killed it, or you swiped it away |
- iOS names the states exactly like the table: Not running → Inactive → Active, then Background → Suspended when you leave.
- An app gets a few seconds in the background to save its work (up to about 30 seconds if it asks for extra time). Then it’s suspended, unless it uses an approved background mode (audio, navigation, calls, background downloads).
- A suspended app gets no warning when it’s terminated. That’s why it must save state when going to the background.
- If the user force-quits an app from the app switcher, iOS throws away its saved screen state, and system background transfers for that app are canceled.
- An Android screen is created, started and resumed (visible and active), then paused and stopped when you leave.
Dev note
These are the activity callbacks:onCreate→onStart→onResume, thenonPause→onStop. - A stopped app’s process is cached: kept in memory but not doing anything. When memory runs low, Android kills cached processes, starting with the least recently used.
- When the process is killed, the screen’s saved instance state survives. When the user comes back, Android recreates the screen and the app should restore it as if nothing happened.
- OEM battery savers on some brands (Xiaomi, Huawei, OnePlus, Samsung “sleeping apps”) kill background apps far more aggressively than stock Android.
Why does the OS kill apps?
- Memory: another app (often the camera or a game) needs RAM, so the OS frees it by killing background apps.
- Battery: iOS and Android limit background work to save power. Android’s Doze and App Standby, plus manufacturer battery optimizations, can stop apps completely.
- Updates and restarts: an app update or a phone restart terminates everything.
- Crashes in the background: a crashCrashWhen an app suddenly closes or stops working because of an unhandled error.Open in glossary → while backgrounded looks to the user like “the app forgot everything”.
Try it: the lifecycle state machine
Press the actions below and watch the app move between states. The panel explains what the app should do at each step, which callbacks the developer gets, and what must survive. Switch between iOS and Android names at the top.
Lifecycle state machine
Press an action and watch the ShopCo app move between states.
Start here
ShopCo is not running yet. Press Open to launch it, then try the other actions. The diagram shows the lifecycle state, the phone shows what the user sees.
The app should
- Each step lists what the app must do or preserve at that moment.
Test idea
Follow the path a real user takes: open, browse, leave, come back later.
Callbacks the developer sees (iOS)
None yet
- State
- Not running
- In memory
- No
- Runs code
- No
Background tasks
Some work must continue after the user leaves. Each type has its own rules and its own bugs.
| Task | Example | How it keeps running | What to test |
|---|---|---|---|
| Downloads / uploads | Offline maps, a podcast, uploading an ID photo | iOS background transfer session, Android WorkManager or a foreground service | Leave during transfer: does it finish? Is progress correct on return? What if the network drops? |
| Location | Running tracker, delivery driver app | Background location permission, usually a visible indicator | Lock the phone for 10 minutes: is the route complete, without gaps? |
| Music and audio | Spotify, audiobooks | Background audio mode / media notification | Lock screen controls, headphones, calls while playing |
| Background refresh | News app showing fresh articles on open | iOS Background App Refresh, Android WorkManager. Runs when the system decides | Turn Background App Refresh off: does the app still work and refresh on open? |
| Push notifications | “Your order has shipped” | Delivered by Apple / Google, not by the app | Tap them with the app in foreground, background and killed |
What to test
Leaving and coming back
- Switch apps (via the app switcher, and via a notification from another app) and come straight back.
- Go Home and return after different gaps: 5 seconds, 5 minutes, 1 hour, the next morning. Each gap catches different bugs.
- Kill the app from the app switcher, then reopen. Expect a fresh start, but saved data (cart, login, settings) must still be there.
- Simulate the OS killing the app (see the tools section) and reopen. Expect to land on the same screen with typed data restored.
- Use the phone heavily in between: open the camera, a game and a few other apps, then come back. This creates real memory pressure.
What must survive
- The current screen and the navigation back stack.
- Typed data: forms, search queries, half-written messages, filters. See state persistenceState persistenceWhether the app remembers what the user did after navigating away, rotating, or restarting.Open in glossary →.
- Scroll position in long lists.
- Media position and play/pause state.
- Work in progress: uploads, downloads, a payment that was being processed.
Coming back after a long time
- Stale data: prices, stock, balances, chat messages and delivery status should refresh on return (or at least show when they were last updated).
- Session expiry: banking and health apps end the sessionSessionThe period during which a user stays logged in without entering their credentials again.Open in glossary → after a few minutes in the background. On return, the app should ask you to log in right away, not show stale personal data and then fail on the first action.
- Time-based content: “Today” labels, countdowns, expired offers and OTP codes are correct after midnight or after hours away.
Opening from outside the app
A push notificationPush notificationA message an app sends to the device that appears even when the app is closed.Open in glossary → or a deep linkDeep linkA link that opens a specific screen inside an app instead of just its home screen.Open in glossary → must open the right screen in all three situations (more in Push notifications and Deep links):
| App state when tapped | Expected result |
|---|---|
| Foreground | Navigates to the target (or shows an in-app banner first) |
| Background / suspended | Resumes and navigates to the target |
| Killed / not running | Cold starts directly on the target (after login if needed), with a sensible Back |
Privacy in the app switcher
The app switcher shows a snapshot of each app’s last screen. Anyone looking at the phone can see it. Banking, health, password and messaging apps should blur it or cover it with the app logo. Open the app switcher on every screen that shows personal data and look closely.
Common bugs
| # | Bug | What you see | Typical severity |
|---|---|---|---|
| 1 | State lost after OS kill | Back on the home screen with an empty form or empty cart | High |
| 2 | Sensitive data in the app switcher | Balance, card number or messages visible in the snapshot | High (privacy) |
| 3 | Stale data on return | Old balance, prices or stock after hours in the background | Medium–High |
| 4 | Expired session not detected | Logged-in screen with old data until an action fails with a vague error | High |
| 5 | Notification opens the wrong screen | Tapping “Your order shipped” opens the home screen when the app was killed | Medium |
| 6 | Background upload or download stops | Progress stuck at 40% forever, no error, no retry | High |
| 7 | Crash on restore | App crashes when reopened after being killed in the background | Critical |
| 8 | Duplicate screens | Each notification tap stacks another copy of the screen; Back has to be pressed many times | Low–Medium |
| 9 | Location gaps | A run or delivery route has straight lines where tracking stopped in the background | High (for that app) |
| 10 | Media restarts from zero | A podcast or video starts over after a warm resume | Medium |
Find the bug
Northbank is a banking app with six lifecycle bugs. Use the device controls to send it to the background, wait, let the OS kill it, open the app switcher and send a push notification. The phone’s clock moves when you wait. Watch the network log: what the app does (and doesn’t) request is a big clue.
🐞 Bug hunt: Northbank banking app
This demo has 6 hidden bugs. Explore it like a tester, then check your findings.
Good morning,
Alex
Main account · ••• 2210
€4,812.50
Recent
Device controls
Northbank: in the foreground. Tap its icon on the Home screen to open it.
Network log
- Requests the app sends appear here…
What happened
- Use the device controls to send the app to the background…
- 1
Hint: On the accounts screen, open the App switcher and look at the Northbank card.
- 2
Hint: Go Home, Wait 2 min, then reopen the app. Compare the "Updated" time with the clock, then tap refresh.
- 3
Hint: Fill in a transfer, Go Home, tap OS kills app, then reopen Northbank from its icon.
- 4
Hint: Compare: Send push and tap it with the app in the background, then again after OS kills app.
- 5
Hint: Start the ID upload in Verify ID, Go Home before it finishes, then come back.
- 6
Hint: Go Home, Wait 30 min, reopen the app, then try to refresh or send a transfer.
Tools & how-to
Simulate the OS killing your app (keeps saved state):
- Open the app, go to a screen with typed data, press Home.
- Run
adb shell am kill com.example.app. It only kills the app if it’s in the background, just like the system would. - Reopen the app from the app switcher (Recents). It should restore the screen and the data.
“Don’t keep activities”: in Settings › System › Developer options, turn on Don’t keep activities. Every screen is destroyed as soon as you leave it, so any screen that doesn’t save its state shows the bug immediately. Also try Background process limit › No background processes. Turn both off again when you’re done, as they make the whole phone behave strangely.
Other useful commands:
adb shell am force-stop com.example.app # like "Force stop" in Settings (state is NOT kept)
adb shell am start -W -a android.intent.action.VIEW -d "shop://order/4521" com.example.app # deep link
adb shell dumpsys deviceidle force-idle # push the device into Doze
adb shell dumpsys deviceidle unforce # leave DozeWatch what happens with logcatLogcatAndroid's system log, read with adb logcat, where apps write errors and crash details.Open in glossary → in Android Studio while you test: you’ll see the process die and restart.
Simulate the OS killing your app (keeps saved state): Apple’s recommended way is to run the app from Xcode, press Home in the app so it goes to the background, then click Stop in Xcode. Relaunch it: state restoration should bring you back. Don’t swipe it away in the app switcher for this test, because a force-quit deletes the saved state on purpose.
Without Xcode (TestFlight builds): open many heavy apps (camera, a few games, video) and come back after a while. Older iPhones with less memory kill background apps much sooner.
Useful Simulator tools:
- Debug › Simulate Memory Warning sends a memory warning to the app (it does not kill it, but badly built apps sometimes crash or drop data).
- Push notification:
xcrun simctl push booted com.example.app payload.apns, or drag an.apnsfile onto the Simulator. - Deep link:
xcrun simctl openurl booted "shop://order/4521". - Background App Refresh: turn it off for your app in Settings › General › Background App Refresh to test the “nothing happened in the background” path.
Example test cases
TC-BG-001Warm resume keeps screen and typed datapositivehigh
Preconditions
- Transfer screen open with recipient and amount filled in
Steps
- Press Home
- Wait 30 seconds
- Reopen the app from the app switcher
Expected result
The transfer screen is shown with the recipient and amount exactly as typed.
TC-BG-002State is restored after the OS kills the appedgehigh
Preconditions
- Android device with adb
- Transfer screen open with data filled in
Steps
- Press Home
- Run adb shell am kill <package>
- Reopen the app from Recents
Expected result
The app cold-starts on the transfer screen with all fields restored. No crash.
TC-BG-003App switcher snapshot hides sensitive datapositivehigh
Steps
- Open the accounts screen with the balance visible
- Open the app switcher
Expected result
The Northbank card shows a blurred screen or the app logo. No balance, names or account numbers are readable.
TC-BG-004Expired session is detected on returnnegativehigh
Preconditions
- Session timeout is 15 minutes
Steps
- Open the accounts screen
- Press Home
- Wait 16 minutes
- Reopen the app
Expected result
The login screen appears immediately. No balance or transactions are shown before logging in. After login the user returns to the accounts screen.
TC-BG-005Notification opens the target screen when the app is killededgemedium
Preconditions
- App terminated (swiped away or killed by the system)
Steps
- Send a "payment received" push to the device
- Tap the notification
Expected result
The app starts directly on the transaction details. Back leads to the accounts screen.
TC-BG-006Data is refreshed after a long time in the backgroundpositivemedium
Preconditions
- A second test account can send money to the user
Steps
- Open the accounts screen and note the balance
- Press Home
- Send €250 from the second account
- Wait 5 minutes and reopen the app
Expected result
The balance includes the €250 without a manual refresh, and the "Updated" time is current.
TC-BG-007Upload continues when the app is backgroundededgehigh
Steps
- Start uploading a 4 MB ID photo
- At about 30%, press Home
- Wait 1 minute
- Reopen the app
Expected result
The upload has completed (or shows its real progress). If it failed, a clear error with a Retry option is shown.
Tip: click a test case to expand it.
Checklist
Background and foreground checklist
0 of 13 checked
Check your understanding
Quick quiz
0/5 answered · 0 correct
1.You press Home. A few seconds later the app is in memory but runs no code. Which state is it in?
2.The OS killed the app in the background to free memory. The user did NOT swipe it away. What should happen when they reopen it?
3.Which Android developer option destroys each screen as soon as you leave it?
4.A banking app shows the account balance in the app switcher. What kind of issue is this?
5.Tapping a push notification works when the app is in the background, but opens the home screen when the app was killed. What should you do?
Key takeaways
- Apps move through not running, active, inactive, background, suspended and terminated. Each transition is a test idea.
- The OS kills background apps to save memory and battery, without warning. Users expect to come back to the same screen and data anyway.
- Test different gaps (seconds, minutes, hours), OS kill vs swipe away, and “Don’t keep activities” on Android.
- After a long absence: refresh stale data and check the session before showing personal data.
- Notifications and deep links must work from foreground, background and killed states.
- Check the app switcher snapshot on every screen with personal data. Related reading: Interruptions.
Finished this page?Nice work, this page is complete!
Mark it as done to track your progress. It's saved in this browser, no account needed.
Its review cards are now in Bites ⚡