41. Testing process death
A checkout screen works after rotation but loses the cart when the user returns after a long time in another app. What is happening and how do you fix it?
- A.The ViewModel was garbage collected because of a memory leak; add more RAM
- B.The OS killed the backgrounded process; the ViewModel was lost, so save key state with SavedStateHandle or persistent storage and restore it
- C.The user cleared the app cache manually; nothing can be done
- D.Rotation and backgrounding are the same, so the bug must be on the server
Show answer
Answer: B. The OS killed the backgrounded process; the ViewModel was lost, so save key state with SavedStateHandle or persistent storage and restore it
ViewModels survive configuration changes but not process death. Android may kill a background process to free memory, then recreate the screen when the user returns. Small UI state should go into SavedStateHandle, and important data like a cart should be persisted to a database. Test with the "Don't keep activities" option or adb shell am kill.
42. Slow cold start
An Android app takes 3 seconds to show its first screen on a cold start. Profiling shows many SDKs initialised in Application.onCreate. What is the most effective improvement?
- A.Defer or lazily initialise non-critical SDKs, move work off the main thread, and add a Baseline Profile
- B.Show a longer splash screen animation
- C.Increase minSdk to the latest version
- D.Move all code into one large Activity
Show answer
Answer: A. Defer or lazily initialise non-critical SDKs, move work off the main thread, and add a Baseline Profile
Everything in Application.onCreate runs on the main thread before the first frame. Analytics, ads and similar SDKs can usually start later or in the background, for example with App Startup or lazy init. Baseline Profiles let ART precompile hot code paths, which commonly cuts startup time noticeably. Measure with Macrobenchmark.
43. Collecting a cold Flow twice
What does this Kotlin program print, one value per line?
val numbers = flow {
println("start")
emit(1)
emit(2)
}
fun main() = runBlocking {
numbers.collect { println(it) }
numbers.take(1).collect { println(it) }
}- A.start, 1, 2, 1
- B.start, 1, 2, start, 1, 2
- C.1, 2, 1
- D.start, 1, 2, start, 1
Show answer
Answer: D. start, 1, 2, start, 1
A flow built with flow { } is cold: its block runs again from the start for every collector, so "start" prints twice. take(1) cancels the upstream right after the first value, so emit(2) never runs the second time. This is why expensive cold flows shared by several collectors are often converted with stateIn or shareIn.
44. PendingIntent crash on Android 12
After targeting Android 12 (API 31) or higher, creating a PendingIntent with flags set to 0 crashes the app. Why?
- A.PendingIntent was removed in Android 12
- B.The app needs the SCHEDULE_EXACT_ALARM permission for every PendingIntent it creates, including ones used for notifications and widgets
- C.You must explicitly pass FLAG_IMMUTABLE or FLAG_MUTABLE; prefer FLAG_IMMUTABLE unless another app must fill in parts of the intent
- D.PendingIntent flags must be negative numbers
Show answer
Answer: C. You must explicitly pass FLAG_IMMUTABLE or FLAG_MUTABLE; prefer FLAG_IMMUTABLE unless another app must fill in parts of the intent
From API 31, apps must declare whether each PendingIntent is mutable, and leaving it unspecified throws an IllegalArgumentException. Immutable is safer because the receiving app cannot change the wrapped intent. Mutable is only needed for cases like inline reply or bubbles where the system adds data.
45. Foreground service fails on Android 14
Your app targets Android 14 (API 34). Starting a foreground service that tracks a running workout now throws an exception. What is required?
- A.Declare a foregroundServiceType for the service in the manifest (such as health or location) and request the matching FOREGROUND_SERVICE_* permission
- B.Nothing can be done; foreground services are banned on Android 14
- C.Replace the service with a manifest BroadcastReceiver, because Android 14 only allows long-running work such as workout tracking inside receivers
- D.Show a Toast before calling startForeground
Show answer
Answer: A. Declare a foregroundServiceType for the service in the manifest (such as health or location) and request the matching FOREGROUND_SERVICE_* permission
Apps targeting Android 14 must declare at least one foreground service type for each foreground service, and each type has its own permission. Missing it throws an exception when the service is started. Types make the purpose explicit and let Google Play review whether the service is justified.
46. Exported activity loading any URL
An exported Android activity reads a "url" extra from its intent and loads it in a WebView with JavaScript enabled and a JavaScript interface to native code. What is the risk?
- A.None; exported only controls whether the activity gets a launcher icon, and other apps can never start an activity in a different app with their own extras
- B.Only slower page loads
- C.Exported only matters on rooted phones
- D.Any installed app can launch it with a malicious URL that then calls the native bridge; validate the URL against an allowlist, or set exported to false if outside apps do not need it
Show answer
Answer: D. Any installed app can launch it with a malicious URL that then calls the native bridge; validate the URL against an allowlist, or set exported to false if outside apps do not need it
An exported component can be started by any app on the device with any extras it chooses. Loading untrusted URLs into a WebView that exposes native methods lets attacker pages run code with your app permissions. Keep components unexported by default and treat all incoming intent data as untrusted input.
47. FCM handler skipped in background
You send FCM messages with a "notification" block plus data. When the Android app is in the background, onMessageReceived is not called and your custom handling never runs. Why?
- A.FCM is disabled for apps in the background
- B.Background delivery needs the RECEIVE_BOOT_COMPLETED permission, and without it FCM drops every message for apps that are not in the foreground
- C.In the background, the system itself shows messages that have a notification block and skips onMessageReceived; send data-only messages if the app must handle them
- D.onMessageReceived only works in debug builds
Show answer
Answer: C. In the background, the system itself shows messages that have a notification block and skips onMessageReceived; send data-only messages if the app must handle them
FCM treats messages with a notification payload as display messages: in the background the SDK posts them to the system tray automatically. onMessageReceived runs for them only in the foreground, while data-only messages reach it in both states. Data-only messages still have delivery limits, so keep their handling short.
48. Data class holding an array
Why does Photo(1, byteArrayOf(1, 2)) == Photo(1, byteArrayOf(1, 2)) return false?
- A.Data classes are not allowed to hold arrays
- B.Generated equals() compares arrays by reference
- C.The first property is compared as a string
- D.byteArrayOf fills arrays with random contents
Show answer
Answer: B. Generated equals() compares arrays by reference
Generated equals() calls equals() on each property, and arrays inherit identity equality from Object. Two arrays with the same contents are still different objects. Use List<Byte>, or override equals and hashCode with contentEquals and contentHashCode.
49. Handler on a child coroutine
A crash still happens even though the inner launch has a CoroutineExceptionHandler. Why?
scope.launch {
launch(CoroutineExceptionHandler { _, e -> log(e) }) {
throw IOException("boom")
}
}- A.CoroutineExceptionHandler works only with async builders
- B.The handler must be the first element in every context
- C.Handlers are always ignored when running on Dispatchers.IO
- D.Children pass errors to the parent; handlers work at the root
Show answer
Answer: D. Children pass errors to the parent; handlers work at the root
In structured concurrency, a failing child propagates its exception up to its parent. Only a handler on the root coroutine (or the scope) is used for uncaught exceptions. Put it in the scope, or catch the error inside the child.
50. Child list never skips
OrderList recomposes every time the parent does, even when orders did not change. Why?
@Composable
fun OrdersScreen(orders: List<Order>, query: String) {
SearchBar(query)
OrderList(orders.filter { it.isActive })
}- A.LazyColumn always recomposes along with its parent
- B.Composables with list parameters can never skip
- C.The theme forces every child to recompose each time
- D.filter returns a new list instance, so it looks changed
Show answer
Answer: D. filter returns a new list instance, so it looks changed
Under strong skipping (default with Kotlin 2.0.20+ Compose compiler), unstable parameters such as List are compared by instance. A new list from filter each time is a new instance. Hoist the filtering into the ViewModel or wrap it in remember(orders).
51. Content under the status bar
After raising targetSdk to 35, screens on Android 15 draw under the status and navigation bars. Why?
- A.It is a bug in Android 15 that a patch will fix
- B.The app theme lost its colorPrimary attribute
- C.Apps targeting 35 are edge-to-edge; handle insets
- D.targetSdk 35 removes support for all toolbars
Show answer
Answer: C. Apps targeting 35 are edge-to-edge; handle insets
Apps targeting Android 15 (API 35) are displayed edge-to-edge by default. Use Scaffold insets, WindowInsets modifiers like safeDrawingPadding, or ViewCompat inset listeners so content avoids system bars.
52. Decryption fails after new fingerprint
An app encrypts a token with a Keystore key that requires biometric authentication. After the user adds a new fingerprint, decryption fails with KeyPermanentlyInvalidatedException. Why?
- A.All Keystore keys expire automatically after 30 days
- B.New biometric enrollment invalidates such keys by default
- C.The token was stored in the wrong app folder
- D.Adding a fingerprint deletes all app data
Show answer
Answer: B. New biometric enrollment invalidates such keys by default
Keys created with user authentication are invalidated on new biometric enrollment by default (setInvalidatedByBiometricEnrollment is true). Catch the exception, delete the key, and ask the user to sign in again to re-create it.
53. Manifest receiver never fires
A receiver declared in the manifest for an implicit broadcast stopped working when the app targeted Android 8.0+. What should it use instead?
- A.A higher priority value in the intent filter
- B.android:exported="false" set on the receiver
- C.A sticky broadcast sent from the app itself
- D.A runtime-registered receiver or WorkManager
Show answer
Answer: D. A runtime-registered receiver or WorkManager
Since Android 8.0, apps cannot receive most implicit broadcasts through manifest receivers. Register receivers in code while the app is running, or use WorkManager with constraints (such as network) for background reactions.
54. Observer called twice after back
A fragment observes LiveData with observe(this) in onViewCreated. After navigating away and back, each update fires the callback twice. Why?
- A.The fragment outlives its view; use viewLifecycleOwner
- B.LiveData always delivers each value twice
- C.onViewCreated runs twice per view creation
- D.The ViewModel was created twice by mistake
Show answer
Answer: A. The fragment outlives its view; use viewLifecycleOwner
A fragment on the back stack keeps living while its view is destroyed and recreated. Observing with the fragment as owner adds a new observer each time the view is recreated. viewLifecycleOwner removes observers when the view is destroyed.
55. Duplicate screens from notification taps
Tapping a chat notification several times stacks several copies of the same ChatActivity. What prevents duplicates when it is already on top?
- A.Start it with FLAG_ACTIVITY_SINGLE_TOP and handle onNewIntent
- B.Call finish() in onCreate of every ChatActivity
- C.Declare the activity with android:exported set to false
- D.Use FLAG_ACTIVITY_NO_ANIMATION on the intent
Show answer
Answer: A. Start it with FLAG_ACTIVITY_SINGLE_TOP and handle onNewIntent
With singleTop behaviour, if the target Activity is already at the top of the task, Android delivers the new intent to onNewIntent instead of creating another instance. The Activity should then update itself from the new intent data. Apps using a single Activity with Navigation often route the intent to a destination instead.
56. Periodic sync every 5 minutes
A developer schedules a WorkManager PeriodicWorkRequest to sync every 5 minutes, but it runs only about every 15 minutes. Why?
- A.WorkManager rounds all intervals up to one hour
- B.The minimum repeat interval for periodic work is 15 minutes
- C.The phone must be charging for periodic work to run
- D.Periodic work only runs while the app is visible
Show answer
Answer: B. The minimum repeat interval for periodic work is 15 minutes
WorkManager enforces a 15-minute minimum for periodic work to protect battery, and Doze and app standby buckets can delay it further. Needs for near real-time updates are better met with push messages that trigger a sync, or a foreground service when the user is actively waiting.
57. Gallery app on Android 13
A gallery app targeting Android 13 still requests READ_EXTERNAL_STORAGE and cannot see images. What changed?
- A.Android 13 removed app access to images completely
- B.It must request READ_MEDIA_IMAGES and READ_MEDIA_VIDEO
- C.It must request the CAMERA permission instead
- D.Images are only visible after the phone reboots
Show answer
Answer: B. It must request READ_MEDIA_IMAGES and READ_MEDIA_VIDEO
From Android 13 (API 33), READ_EXTERNAL_STORAGE no longer grants media access for apps targeting it. Apps request READ_MEDIA_IMAGES, READ_MEDIA_VIDEO or READ_MEDIA_AUDIO for the types they need. Android 14 added partial access, where users pick selected photos only.
58. Exposing native code to a WebView
An Android app calls `addJavascriptInterface(bridge, "App")` on a WebView that can navigate to any URL. What is the danger?
- A.The WebView will refuse to load any HTTPS pages
- B.Any page loaded in it can call the exposed native methods
- C.JavaScript is disabled as soon as a bridge is added
- D.The bridge works only with local HTML files
Show answer
Answer: B. Any page loaded in it can call the exposed native methods
Methods annotated with @JavascriptInterface are callable by any script in the WebView, including scripts on third-party or attacker pages. Restrict navigation to trusted origins, expose minimal methods, validate inputs, and consider WebMessage APIs with origin checks.
59. Attacker installs a CA certificate
An attacker convinces a user to install a custom CA certificate on an Android 13 phone to intercept your app's HTTPS traffic. By default, what happens?
- A.All apps trust the new CA and all traffic is readable
- B.Apps targeting API 24+ ignore user-added CAs by default
- C.The phone wipes itself when a CA is installed
- D.Only Wi-Fi traffic is affected, not mobile data
Show answer
Answer: B. Apps targeting API 24+ ignore user-added CAs by default
Since Android 7 (API 24), apps by default trust only system certificate authorities, not ones the user adds. This blocks the simple "install my certificate" attack. Apps that opt in to user CAs in their network security config lose that protection.
60. Raising the minimum OS version
An app raises minSdk from 24 to 26. What happens to users on Android 7.0 devices (API 24)?
- A.They keep their installed version but receive no further updates
- B.Their installed copy is uninstalled automatically by Play
- C.Their app keeps updating, but new features are hidden
- D.They are moved to the beta track automatically
Show answer
Answer: A. They keep their installed version but receive no further updates
Play delivers updates only to devices that meet the new release's requirements, so older devices stay on the last compatible version. The app keeps working there until the server stops supporting it. Check analytics for how many active users are affected before raising minSdk or the iOS deployment target.