Everything the adaptive question bank can teach and test in Android Development, from foundations through advanced practice. Work through it in order, or start practising and let the questions find your level.
activity, service, broadcast receiver and content provider are the only entry points the system can start
•
the system constructs a component and calls its callbacks; an app owns no single main()
•
each app gets its own Linux user ID and process, so another app's files are unreachable without an explicit grant
•
an activity or service missing from the manifest cannot be started, and the failure is a runtime exception rather than a build error
•
android:exported decides whether other apps can start a component, and API 31+ refuses to build one that has an intent filter but no explicit value
•
minSdk is the oldest device that can install, compileSdk is which APIs compile, targetSdk is which behavior changes apply to you
B. The activity lifecycle, configuration changes and process death
•
create/destroy, start/stop and resume/pause are three mirrored pairs, always entered and unwound in that order
•
started means visible, resumed means focused; a dialog on top leaves the activity started but paused
•
the incoming activity cannot resume until onPause returns, so slow work there is a visible stall
•
camera, sensors and animations pair with onStart/onStop, because a merely paused activity can still be on screen
•
the Bundle argument is non-null only on recreation, which is how you tell a cold start from a restore
•
it runs when the activity *may* be killed, not when the user finishes it, and it is sized for small transient UI state only
•
rotation, locale, font scale and dark-mode switches destroy and recreate the activity unless configChanges claims them
•
a ViewModel survives a configuration change but dies with the process; only saved state or disk survives both
C. Tasks, the back stack and launch modes
•
a task holds activities last-in-first-out, and Back pops the top one
•
activities from different apps can share one task, so the back stack is a user journey rather than an app
•
standard always creates a new instance; singleTop reuses one only when it is already at the top of the stack
•
a reused instance receives the intent in onNewIntent, and getIntent() keeps returning the original until setIntent is called
•
Up walks the app's declared hierarchy and never leaves the app; Back walks the historical stack and can
D. Intents and intent filters
•
an explicit intent names the component class; an implicit one describes an action and lets the system resolve a handler
•
resolution tests action, category and data, and an implicit intent is delivered only if it passes all three
•
an implicit intent sent to startActivity is given CATEGORY_DEFAULT, so a filter lacking it never matches
•
an exported component's extras arrive from another process and must be validated like any external input
•
since API 30 an app must declare <queries> to see or resolve most other apps' components
•
registerForActivityResult replaces startActivityForResult and must be registered unconditionally during initialization, before STARTED
•
a PendingIntent runs with your app's identity in another process, and API 31+ requires FLAG_IMMUTABLE or FLAG_MUTABLE to be stated
E. Fragments and the View system
•
the fragment's view dies in onDestroyView while the fragment instance lives on, so observers must use viewLifecycleOwner
•
a view binding held past onDestroyView pins the whole detached view hierarchy in memory
•
addToBackStack makes Back reverse a fragment transaction; without it the transaction cannot be undone
•
the View system renders in three passes, and nesting multiplies measure cost — the reason ConstraintLayout exists to flatten hierarchies
•
AndroidView hosts a classic View inside Compose, with an update lambda that runs on recomposition
•
ComposeView embeds Compose UI inside an existing XML layout
F. Compose: composition, recomposition and stability
•
a composable describes the UI for a state; you never mutate a widget, you change state and let it re-run
•
only scopes that *read* a changed State recompose, so a state nobody reads costs nothing to write
•
composables may run in any order, in parallel, be skipped, and re-run every frame, so a side effect in the body fires an unpredictable number of times
•
Compose skips a composable whose parameters are all stable types and equal to the previous composition
•
List can hide a mutable implementation, so passing one defeats skipping; an immutable collection or @Immutable restores it
•
a lambda capturing an unstable value forces the child to recompose even when its visible data is unchanged
•
reading state in the lowest composable that needs it keeps every ancestor out of the recomposition
•
CompositionLocal passes a value down a subtree implicitly instead of threading it through every parameter
G. Compose state and state hoisting
•
remember caches a value across recompositions and nothing more; it dies with the composition
•
without remember a fresh state is allocated each recomposition, so writes look like they are being ignored
•
the read is what registers the scope; a State written but never read triggers no recomposition anywhere
•
rememberSaveable writes into saved instance state, surviving rotation and process death, which remember does not
•
rememberSaveable needs a Bundle-compatible type or an explicit Saver; an ordinary data class is neither
•
a stateless composable takes the value down and sends the event up, leaving exactly one source of truth
•
derivedStateOf recomputes on every source change but notifies readers only when the derived value differs, throttling a fast-changing input
H. Compose side effects
•
LaunchedEffect starts a coroutine on entering composition and cancels then restarts it whenever a key changes
•
LaunchedEffect(Unit) is right for one-shot work and wrong whenever the effect depends on data that can change
•
use DisposableEffect when something must be unregistered; onDispose runs on leaving composition or before a keyed restart
•
a click handler cannot start a LaunchedEffect, so launching from a callback needs rememberCoroutineScope
•
captures the latest value inside a long-lived effect that must not be restarted by a key change
•
SideEffect publishes state to non-Compose code after every successful composition and cannot suspend
I. Compose layout, modifiers and the three phases
•
composition decides what, layout decides where and how big, drawing decides how — and a frame can skip the earlier phases
•
a Compose layout measures each child exactly once, which is why arbitrary multi-pass measurement is rejected
•
a modifier chain applies outside-in, so padding before background insets the color and padding after does not
•
padding placed after clickable falls outside the touch target; placed before, it is inside it
•
a parent passes constraints down and each child reports its own resolved size back up
•
offset { } and graphicsLayer { } read state during layout or draw, so an animation through them skips recomposition entirely
•
Column stacks vertically, Row horizontally, Box overlays children in the same space
•
arrangement distributes children along the main axis; alignment positions them on the cross axis
J. Lazy lists and scrolling
•
LazyColumn composes only what is visible, unlike a Column inside verticalScroll, which composes every child
•
without a key an item's remembered state is bound to its index, so an insertion shifts that state onto the wrong row
•
declaring contentType lets Compose reuse compositions across items of the same shape in a heterogeneous list
•
a vertically scrollable child inside a LazyColumn is measured with infinite height constraints and throws
K. Architecture: layers, ViewModel and unidirectional data flow
•
dependencies point one way, UI → domain → data, and never back up
•
the repository owns the merge of network and cache so the UI observes one authoritative stream
•
state flows down and events flow up; the UI never writes state it does not own
•
a ViewModel is scoped to a lifecycle owner and onCleared runs only when that owner is finishing for good, not on rotation
•
an Activity, View or Context stored in a ViewModel leaks across the very configuration change the ViewModel exists to survive
•
SavedStateHandle gives a ViewModel key-value state that survives process death, which a plain field does not
•
exposing a single immutable UiState avoids the inconsistent intermediate frames that several independent streams produce
•
Hilt builds on Dagger to supply dependencies instead of constructing them inline, which is what makes a layer testable
L. Coroutines, flows and lifecycle-aware collection
•
work launched in viewModelScope is cancelled automatically when the ViewModel is cleared
•
a suspend function moves itself off the main thread with withContext, so no caller has to know where it runs
•
collect suspends until the flow finishes, so two collects written sequentially in one coroutine starve the second
•
repeatOnLifecycle(STARTED) cancels collection when the app backgrounds and restarts it on return, whereas launchWhenStarted only suspends and leaves the producer hot
•
the Compose equivalent; plain collectAsState keeps consuming while the app is in the background
•
StateFlow always holds a value, drops intermediate emissions under load, and skips an emission equal to the current one
M. Navigation
•
one activity hosts many destinations, so navigating is a back-stack operation rather than an activity launch
•
each graph has a fixed start destination, and it is the last screen Back reaches before leaving the app
•
popUpTo pops up to a destination, and inclusive pops that destination too — how a login screen is erased from history
•
prevents stacking a second copy of the destination already on top of the back stack
•
arguments should carry an identifier the destination re-reads from its own layer, not a serialized object that can go stale
N. Persistence: Room, DataStore, files and scoped storage
•
app-specific directories need no permission and are removed on uninstall; shared media storage is neither
•
since API 29 an app reaches other apps' media through MediaStore or the Storage Access Framework, not through raw file paths
•
Room validates @Query SQL against the schema at build time, so a typo is a compile error rather than a runtime crash
•
a suspend DAO function is one-shot; a Flow return re-emits whenever the queried tables change
•
Room refuses main-thread database access by default instead of letting it become an ANR
•
bumping the schema version without a Migration throws on open, and fallbackToDestructiveMigration silently drops the data instead
•
DataStore is asynchronous and transactional; SharedPreferences exposes a synchronous commit() that blocks its caller
•
key-value stores sit in the sandbox unencrypted, so tokens and keys do not belong in them
O. Networking
•
a network call on the main thread throws NetworkOnMainThreadException by design, not as a warning
•
INTERNET is a normal permission granted at install, so there is no runtime prompt to handle for it
•
plain HTTP is refused since API 28 unless a network security configuration opts that domain in
•
a connected network says nothing about your server, so timeouts and retries still have to exist
•
Retrofit turns an interface into typed HTTP calls; OkHttp is the client underneath it that actually moves bytes
P. Background work, services and execution limits
•
WorkManager is for deferrable guaranteed work; a foreground service is for immediate work the user is actively aware of
•
since API 26 a backgrounded app cannot start a plain background service; the call throws
•
a foreground service must post a notification and, since API 34, declare a foregroundServiceType backed by a matching permission
•
network, charging and idle constraints defer work rather than fail it, and the work still runs after a reboot
•
enqueueUniqueWork with KEEP, REPLACE or APPEND is what stops a relaunch from queueing duplicate jobs
•
Doze batches deferred work into maintenance windows, so a guaranteed wake-up needs an exact alarm and its own permission
•
since API 26 most implicit broadcasts no longer wake a manifest-declared receiver, so register at runtime instead
Q. Permissions
•
normal permissions are granted at install; dangerous ones must be requested at runtime and can be revoked afterwards
•
a grant can be revoked while the app is not running, so the check belongs at the point of use, not at startup
•
the result arrives in a callback, so the line after the request executes before the user has answered
•
shouldShowRequestPermissionRationale is true only after one denial and before a permanent one, which is the only moment an explanation helps
•
once denied for good the system shows no dialog and returns denied immediately; the only route left is Settings
•
the photo picker, the Storage Access Framework and a capture intent return the same data with no permission requested at all
R. Notifications and channels
•
since API 26 a notification posted without a channel is not shown at all
•
importance, sound and vibration belong to the user once a channel exists; the app cannot raise them again in code
•
since API 33 POST_NOTIFICATIONS is a runtime permission the user can deny
•
posting with an id already in use replaces that notification instead of adding a second one
S. Resources and configuration qualifiers
•
the system selects from qualified folders at runtime, so -night, -land and -es need no branching in code
•
an unqualified default resource is required, or a configuration you did not anticipate fails at lookup
•
drawables are qualified mdpi through xxxhdpi, and Android scales the nearest available bucket when one is missing
•
dp is density-independent and resolves to pixels at runtime, so a hardcoded px is a different physical size on every device
•
sp additionally honors the user's font-size setting, which is why text must never be sized in dp
•
layout-direction-aware attributes mirror automatically in RTL locales; left and right stay put
T. Build: Gradle, variants, R8 and delivery
•
a build variant is the cross product of product flavor and build type, which is where a variant explosion comes from
•
the debug type is debuggable and auto-signed with a shared debug key; shrinking and your own signing key belong to release
•
R8 strips unreachable code and renames what remains, which is why reflection and serialization break in release builds only
•
a keep rule names the reflectively-referenced classes and members R8 must not remove or rename
•
an update must be signed by the same key, and Play App Signing holds that key so a lost upload key stays recoverable
•
Play generates per-device APKs from an App Bundle; a device installs an APK, never the .aab itself
•
versionCode is the integer Play orders releases by and must increase; versionName is a display string with no rules
•
internal, closed, open and production tracks trade audience size against feedback risk
•
a percentage rollout limits blast radius and can be halted before it reaches everyone
U. Performance: jank, startup, memory and ANRs
•
jank is a missed frame deadline against the display's refresh interval, so it is a worst-case problem, not an average one
•
an ANR fires because the main thread did not return in time, regardless of how much total work the app is doing
•
a shipped profile lets ART precompile the hot startup and scroll paths, improving cold start before any of your code runs
•
a cold start creates the process, a warm one recreates the activity, a hot one only brings it forward
•
a debug build skips R8 and adds instrumentation, so profiling it measures an app you never ship
•
a static field, an unremoved listener or an inner-class Handler holding an Activity keeps its entire view tree alive past recreation
V. Accessibility
•
an icon-only control needs a description a screen reader can announce, and a purely decorative image must be explicitly null so it is skipped
•
an interactive element needs roughly 48dp of touch target no matter how small it is drawn
•
meaning carried only by color is invisible to many users, and text still needs sufficient contrast against its background
•
Compose publishes a separate semantics tree, and mergeDescendants and clearAndSetSemantics control what services and UI tests see
W. Testing
•
local JVM tests are fast but have no real framework; instrumented tests run on a device and pay for it in wall-clock time
•
calling an Android framework class from a local unit test hits a stub that throws unless it is faked or Robolectric provides it
•
a hardcoded dispatcher is untestable; injecting it is what lets a test substitute a scheduler and control virtual time
•
the Compose test rule matches nodes through the semantics tree and synchronizes with the clock, so an explicit sleep is both slow and wrong
•
a hand-written fake exercises the real contract, where a mock only replays the interactions the test already assumed
X. Material theming and dynamic color
•
MaterialTheme supplies color scheme, typography and shapes to everything composed beneath it
•
read the current values from MaterialTheme.colorScheme rather than hard-coding them
•
MaterialTheme.typography names the roles (display, headline, body, label) so text stays consistent
•
Android 12+ can derive the scheme from the user wallpaper, so the palette is not yours to fix
Keentune is not affiliated with or endorsed by the organizations whose documentation informs these maps.
All exam, test, and product names and trademarks are the property of their respective owners and are used here for identification and reference only. Keentune is independent study practice — not affiliated with, authorized, or endorsed by any of these organizations.