ANR & Memory Management Quiz
PERFORMANCE › Runtime
How long can the main thread block an input event before the system raises an ANR?
- 2 seconds
- 5 seconds
- 10 seconds
- 20 seconds
Answer: 5 seconds
Input dispatching that isn't handled within 5 seconds triggers a user-perceived ANR, the core Android vitals metric.
A foreground app's BroadcastReceiver.onReceive() must return within how long to avoid an ANR?
- 10 seconds
- 5 seconds
- 60 seconds
- 200 seconds
Answer: 10 seconds
Foreground broadcast receivers have a 10-second limit (background receivers get up to 60s); long work must be moved off onReceive().
Which approach correctly prevents an ANR when a button tap triggers a long network request?
- Run the network request directly inside onClick on the main thread
- Do the work on Dispatchers.IO, then update UI on the main dispatcher
- Wrap the request in runOnUiThread { } so it posts to the UI thread
- Raise the input-dispatch ANR timeout via a manifest <application> flag
Answer: Do the work on Dispatchers.IO, then update UI on the main dispatcher
Network I/O must run off the main thread; a coroutine on Dispatchers.IO does the work and you update UI back on the main dispatcher. runOnUiThread still runs on the main thread, and the timeout cannot be changed in the manifest.
Why does storing an Activity reference in a static (companion object) field cause a memory leak?
- The static field keeps the Activity reachable, so its views can't be GC'd
- Static fields just reserve extra heap space and make the app use more memory
- Reading a static field triggers a full garbage collection on every access
- It moves the Activity into native memory, where the Java GC can't see it
Answer: The static field keeps the Activity reachable, so its views can't be GC'd
A static field outlives the Activity, so even after onDestroy the GC cannot reclaim the Activity or the views it holds.
What is the recommended fix for a Handler/Runnable inner class that leaks its enclosing Activity?
- Make the Handler a non-static inner class of the enclosing Activity
- Make it static, hold the Activity weakly, and clear callbacks in onDestroy
- Force garbage collection by calling System.gc() inside onDestroy()
- Mark the enclosing Activity reference field with @Volatile
Answer: Make it static, hold the Activity weakly, and clear callbacks in onDestroy
A static class avoids the implicit outer reference, and a WeakReference lets the Activity be collected; pending messages should also be removed in onDestroy.
How is a SoftReference's referent cleared compared to a WeakReference's?
- Both are cleared at the same time, on the same GC cycle.
- Soft clears at the next GC, while weak can survive until OOM.
- Neither one is cleared automatically by the garbage collector.
- Soft stays until heap pressure; weak clears at the next GC.
Answer: Soft stays until heap pressure; weak clears at the next GC.
WeakReferences clear eagerly at the next GC; SoftReferences are kept as long as possible and only cleared under memory pressure, which is why they suit memory-sensitive caches.
Your app receives onTrimMemory(TRIM_MEMORY_UI_HIDDEN). What is the appropriate action?
- Kill the process right away to release all of its allocated memory
- Allocate a buffer to reserve RAM before the system reclaims it
- Free UI memory like bitmaps and caches that are no longer visible
- Ignore it, since the app is still running in the foreground
Answer: Free UI memory like bitmaps and caches that are no longer visible
TRIM_MEMORY_UI_HIDDEN signals the UI is no longer visible, the best moment to free UI-tied allocations like bitmaps and view caches to reduce the chance of being killed.
A foreground Service's lifecycle callbacks (onCreate, onStartCommand, onBind) must complete within how long before the system raises an ANR?
- 20 seconds
- 5 seconds
- 10 seconds
- 200 seconds
Answer: 20 seconds
Foreground Service lifecycle execution has a 20-second limit (background services get 200 seconds); blocking longer triggers an ANR.
You call startForegroundService() but the started Service never calls startForeground() within the allowed time. What happens?
- Nothing happens; the service just continues running in the background
- The system silently promotes the service to the foreground for you
- The app is crashed with RemoteServiceException after roughly 5s
- The input-dispatch ANR timeout is temporarily extended for the app
Answer: The app is crashed with RemoteServiceException after roughly 5s
After startForegroundService(), the Service has roughly 5 seconds to call startForeground() with a notification, or the system crashes the app with a RemoteServiceException.
Which API lets you inspect, in production, why your app's process died on a previous run, including whether it was an ANR?
- Debug.getMemoryInfo(), which reports current RAM usage but not past exits
- ActivityManager.getHistoricalProcessExitReasons() returns ApplicationExitInfo
- Runtime.getRuntime().freeMemory(), which shows heap space, not crash history
- Choreographer.getInstance().postFrameCallback(), which schedules drawing callbacks
Answer: ActivityManager.getHistoricalProcessExitReasons() returns ApplicationExitInfo
getHistoricalProcessExitReasons() returns ApplicationExitInfo records (API 30+) whose reason can be REASON_ANR, REASON_LOW_MEMORY, etc., letting you diagnose past deaths in the field.
Why does a ViewModel running a coroutine in viewModelScope NOT leak across a screen rotation?
- Because ViewModel instances live in a static field that the GC ignores
- Because coroutines started in viewModelScope are structurally unable to leak
- Because the ViewModel holds the host Activity in a WeakReference
- It survives config changes; onCleared() cancels viewModelScope on real destroy
Answer: It survives config changes; onCleared() cancels viewModelScope on real destroy
The ViewModel survives rotation (the owner re-attaches) and is cleared only when the owner truly finishes; onCleared() then cancels viewModelScope so its coroutines don't outlive it.
What is StrictMode primarily used for during development?
- Enforcing Kotlin code-style conventions at compile time in the IDE
- Catching main-thread disk/network I/O and leaked Closeables at runtime
- Automatically encrypting all SharedPreferences contents at runtime
- Capping the per-app ART heap allocation to a fixed hard limit
Answer: Catching main-thread disk/network I/O and leaked Closeables at runtime
StrictMode's thread policy flags main-thread disk/network access while its VM policy detects leaked Closeables, SQLite cursors, and Activity instances, surfacing problems early in development.
You are decoding a large photo into a Bitmap and don't need full alpha or color precision. Which change most reduces its in-memory footprint?
- Decode it on the main thread instead of using a background thread
- Keep the decoded bitmap in a static cache for faster reuse later
- Use RGB_565 and increase inSampleSize when decoding
- Call System.gc() right after decoding to force memory to free
Answer: Use RGB_565 and increase inSampleSize when decoding
RGB_565 halves per-pixel cost versus ARGB_8888, and a larger inSampleSize decodes fewer pixels; together they cut the bitmap's memory, the largest allocation in most apps.
A process-wide singleton needs a Context. Which Context should it hold to avoid leaking an Activity?
- context.applicationContext, which lives for the process
- The current Activity context, since it matches the theme
- The Context from the visible View, because it is current
- A ContextWrapper around the Activity, to make it reusable
Answer: context.applicationContext, which lives for the process
applicationContext lives as long as the process, so a long-lived singleton holding it never pins a finished Activity; holding an Activity or View context would leak the whole view tree.