Prepare for Android interview questions grouped by experience level.
Android Interview Question & Answers
0-2 Years
Android is an operating system built on the Linux kernel, primarily designed for touchscreen mobile devices, developed and maintained by Google. It provides the underlying platform, APIs, and application framework that developers build native mobile apps on top of.
The four main components are Activities, which represent a single screen with a user interface, Services, which run in the background without a UI, Broadcast Receivers, which respond to system wide announcements, and Content Providers, which manage shared application data.
An Activity represents a single, focused screen a user can interact with, like a login screen or a settings page. It's the entry point for most user interaction and manages its own lifecycle as the user navigates to, away from, and back to it.
A Fragment is a reusable portion of a user interface that lives within an Activity, allowing a screen to be composed of multiple independent, modular pieces. Fragments have their own lifecycle but are tied to the lifecycle of the Activity that hosts them.
The AndroidManifest.xml file is a required configuration file for every Android app that declares essential information like the app's package name, components such as Activities and Services, required permissions, and minimum supported Android version, letting the system know how to launch and manage the app.
The Activity lifecycle is the sequence of states an Activity moves through as the user interacts with it, including onCreate, onStart, onResume, onPause, onStop, and onDestroy. Each callback gives the developer a place to set up or release resources appropriate to that state.
onPause is called when the Activity is no longer in the foreground but might still be partially visible, like when a dialog appears over it. onStop is called when the Activity is completely hidden from the user, such as when another Activity fully covers it or the user navigates away.
An Intent is a messaging object used to request an action from another app component, such as starting a new Activity, launching a Service, or delivering a broadcast. Intents can be explicit, targeting a specific component, or implicit, letting the system find a component that can handle the request.
An explicit Intent specifies the exact component, like a particular Activity class, that should handle it, commonly used for navigation within the same app. An implicit Intent describes the action to perform, like sharing text, without naming a specific component, letting the system find any app that can handle that action.
A Service is an application component that can run operations in the background without a user interface, such as playing music or handling network transactions, and it continues running even if the user switches to a different app, unless the system needs to reclaim resources.
A started Service runs independently in the background once started and keeps running until it stops itself or is stopped explicitly. A bound Service offers a client server interface that other components can bind to and interact with directly, and it typically runs only as long as something is bound to it.
A Broadcast Receiver is a component that listens for and responds to system wide or app specific broadcast announcements, like the device finishing booting or the battery reaching a low level, letting an app react to events happening outside its own direct control flow.
A Content Provider manages access to a structured set of data, like a contacts database, and exposes it to other applications through a standard interface, allowing controlled sharing of data across app boundaries while enforcing whatever permissions the provider defines.
An Activity is a standalone screen with its own entry in the system's back stack and its own window. A Fragment doesn't exist independently and must be hosted within an Activity, letting a single Activity present multiple Fragments together or swap between them to build more flexible, modular UI.
A layout XML file defines the visual structure of a screen or a portion of a screen declaratively, specifying which views to display and how they're arranged, which Android inflates into actual view objects at runtime rather than requiring the UI to be built entirely in code.
A View is the base class for all UI components in Android, like buttons, text fields, and image views, representing a rectangular area on the screen responsible for drawing itself and handling user interaction events like touches.
A ViewGroup is a special type of View that can contain other Views, acting as a container that defines how its child views are arranged, such as LinearLayout arranging children in a row or column, or ConstraintLayout positioning children based on defined constraints.
LinearLayout arranges its children in a single row or column, which is simple but can require nesting multiple layouts for complex screens. ConstraintLayout lets each view's position and size be defined relative to other views or the parent using constraints, allowing complex, flat layout hierarchies without deep nesting.
An Adapter acts as a bridge between a data source, like a list of items, and a UI component like a RecyclerView or ListView, responsible for creating and binding the views that display each item in the underlying data set.
RecyclerView is a flexible, efficient view for displaying large scrollable lists or grids of data, designed to reuse, or recycle, a limited number of item views as the user scrolls rather than creating a new view for every single item, which significantly improves performance for long lists.
ListView is an older component for displaying scrollable lists that requires more manual work to implement view recycling correctly for good performance. RecyclerView was introduced as a more flexible and performant successor, with built in support for view recycling and configurable layout managers for lists, grids, or staggered layouts.
The Android SDK, Software Development Kit, is the collection of tools, libraries, and APIs provided by Google for building Android applications, including the Android platform APIs, build tools, emulator, and debugging utilities needed to develop and test apps.
An APK, Android Package, is the file format Android uses to distribute and install applications, containing the app's compiled code, resources, assets, and manifest bundled into a single installable package.
Android Studio is the official integrated development environment for Android app development, built on JetBrains' IntelliJ IDEA, providing code editing, debugging, an emulator, and build tools specifically tailored for building Android applications.
Gradle is the build automation tool Android Studio uses to compile code, manage dependencies, and package an Android app into an APK or app bundle, configured through build.gradle files that specify things like target SDK version and library dependencies.
The application context is tied to the overall lifecycle of the application and persists as long as the app is running, useful for operations that shouldn't be tied to a specific screen. An activity context is tied to a specific Activity's lifecycle and is needed for operations like inflating a themed layout or showing a dialog tied to that screen.
A permission is a declaration an app makes, typically in its manifest, requesting access to sensitive data or device capabilities, like the camera or location. Certain permissions considered sensitive must also be explicitly granted by the user at runtime rather than just declared.
A normal permission covers low risk access, like checking network connectivity, and is granted automatically at install time. A dangerous permission covers access to sensitive data or capabilities, like contacts or location, and requires the app to explicitly prompt the user for approval at runtime.
SharedPreferences provides a simple way to store small amounts of key value data persistently, like a user's settings or a flag indicating whether onboarding was completed, without needing to set up a full database for such lightweight storage needs.
Internal storage is private to the app and inaccessible to other apps or the user directly, suitable for sensitive or app specific files. External storage is a shared storage area, historically the SD card, that other apps or the user may be able to access, and it requires appropriate permissions to use.
A Toast is a small, temporary popup message that appears briefly on screen to give the user quick feedback, like confirming an action succeeded, and it automatically disappears after a short time without requiring any user interaction to dismiss.
The res, or resources, folder holds non code assets an app uses, like layout XML files, string values, images, and colors, organized into subfolders so Android can automatically select the appropriate version of a resource based on device characteristics like screen density or language.
A string resource stores text values in an XML file under the res/values folder rather than directly in code, which makes it easier to support multiple languages through localization and keeps user facing text centralized and easy to update without touching application logic.
Declaring a permission in the manifest tells the system and, for dangerous permissions, the user what capabilities or data the app intends to access, and it's a required step before the app can request that access at runtime for permissions that need explicit user approval.
An emulator is a virtual Android device that runs on a developer's computer, simulating a real device's hardware and software environment, letting developers test an app across different device configurations and Android versions without needing physical devices for each one.
Logcat is Android Studio's logging tool that displays system and application log messages in real time, letting developers see debug output, warnings, and errors from their app or the underlying system while it runs, which is essential for diagnosing issues during development.
3-6 Years
I would use a ViewModel to hold the UI state so it survives configuration changes since ViewModels are retained across them, or persist critical form data through the Activity's saved instance state bundle, rather than letting the Activity's recreation silently discard unsaved user input.
I would check for long lived references to the Activity or its context held by singletons, static fields, or listeners that were registered but never unregistered, and use a memory profiling tool to capture a heap dump and trace exactly what's holding the reference alive.
I would decode the image at a scaled down size appropriate for the target ImageView's dimensions rather than loading the full resolution bitmap into memory, and use an established image loading library that handles caching, sampling, and lifecycle awareness rather than managing bitmap decoding manually.
I would use a lifecycle aware approach like coroutines scoped to the ViewModel or lifecycle, so the callback either doesn't fire or safely no-ops if the Activity has already been destroyed, rather than directly updating views from a background thread callback without checking the current lifecycle state.
I would generally favor Fragments for screens that are logically part of a single flow or need to share data easily with sibling screens within the same Activity, and reserve separate Activities for screens with a genuinely distinct entry point or lifecycle, like something launched from outside the app.
I would use SharedPreferences or the newer DataStore for straightforward key value settings, expose the current values and changes through a ViewModel so the UI stays reactive to updates, and avoid reading preferences directly from the UI layer to keep the logic testable.
I would profile the app specifically on a representative lower end device or a throttled emulator configuration, look for excessive work happening on the main thread that a faster device masks, and check whether overdraw from deeply nested or overlapping layouts is contributing to the slowdown.
I would evaluate whether a foreground Service with a persistent notification is appropriate given the user visible nature of the ongoing work, or use WorkManager for deferrable background work that needs to survive process death and respect system battery optimization constraints.
I would only request the permission at the point the user actually tries to use the feature that needs it, rather than upfront at app launch, explain briefly why the permission is needed if the system's rationale prompt appears, and handle the case where the user denies it gracefully rather than crashing or blocking the whole app.
I would follow an MVVM style architecture, putting business logic and state management in a ViewModel that the Activity or Fragment observes, keeping the UI layer focused purely on rendering state and forwarding user actions, which also makes the logic easier to unit test independent of the Android framework.
I would examine the full stack trace and device or OS version details from the crash report to look for patterns, like it only affecting a specific manufacturer or Android version, and try to reproduce the exact conditions, including things like low memory or a specific screen size, that might not show up on a typical development device.
I would inject a fake or mocked version of the repository into the ViewModel for the test rather than hitting a real network, and verify the ViewModel exposes the expected state for both success and failure responses from that dependency, keeping the test fast and independent of actual network conditions.
I would use alternative resource qualifiers so Android automatically selects a layout appropriate to the screen size, and where the difference is more than just spacing, like showing a list and detail pane together on tablets, structure the UI with Fragments so the same components can be recombined differently per form factor.
I would profile what's happening during app startup, look for expensive initialization work happening synchronously on the main thread before the first screen renders, and defer or lazily initialize anything that isn't strictly needed for the very first frame the user sees.
I would use a shared ViewModel scoped to the Activity so both Fragments can observe and update common state without directly referencing each other, which avoids tight coupling between the Fragments and keeps the communication testable.
I would cache API responses locally using a database like Room, have the UI read from that local cache as the source of truth, and sync with the remote API in the background, updating the cache when new data is fetched, so the app remains usable without a live network connection.
I would check whether the adapter's data update is being communicated correctly through methods like notifyDataSetChanged or, preferably, DiffUtil for more targeted updates, and confirm the adapter isn't holding a stale reference to an old list rather than the newly updated one.
I would define the appropriate intent filters in the manifest for the target Activity to handle the deep link URI, make sure the back stack is constructed correctly so the user can navigate back naturally rather than landing in a confusing state, and test the deep link both from a cold start and while the app is already running.
I would flag that the network call belongs in a ViewModel or repository layer rather than directly in the Activity, since coupling network logic to the Activity's lifecycle makes it harder to test and prone to leaking callbacks if the Activity is destroyed before the call completes, and suggest the appropriate architectural pattern the project already uses.
I would enable resource shrinking and code shrinking through the build configuration, review whether large unused libraries or duplicate resources have accumulated over time, and consider using an app bundle format so the store can deliver device specific optimized downloads instead of one large universal APK.
I would check whether code shrinking and obfuscation rules are stripping or renaming something the app relies on through reflection, like a data class used with a serialization library, and add appropriate keep rules once the specific class or method causing the crash is identified from the release build's stack trace.
I would validate individual fields as the user moves between them rather than only on final submission, show inline error messages next to the specific field rather than a generic banner, and make sure the submit action stays disabled or clearly indicates what's still needed rather than letting the user submit and only then discover what's wrong.
I would confirm the SDK's initialization is actually the bottleneck using a profiler rather than assuming, check whether it offers a lazy or deferred initialization option, and move its setup off the critical startup path if the data it collects doesn't need to be available from the very first frame.
I would use a SwipeRefreshLayout wrapping the RecyclerView, trigger a fresh network call when the user pulls down, and make sure the refreshing indicator is dismissed correctly whether the call succeeds or fails so the user isn't left with a spinner stuck on screen.
6-8 Years
I would adopt a modularized architecture where features live in separate Gradle modules with clearly defined boundaries and interfaces, establish shared core modules for common infrastructure like networking and design system components, and set up build tooling so teams can build and test their module independently without needing the entire app.
I would analyze ANR traces collected from crash reporting to identify common patterns, like a specific screen or operation consistently blocking the main thread, check for synchronous IO or heavy computation happening where it shouldn't, and prioritize fixes based on which patterns affect the largest share of affected users.
I would standardize on WorkManager as the primary mechanism for deferrable background work needing guarantees around persistence and constraints, establish clear guidelines for when a foreground Service is actually necessary versus WorkManager being sufficient, and avoid letting individual features implement inconsistent, one off background processing approaches.
I would use product flavors to build variants sharing the same core codebase, feature flag or conditionally include heavier functionality in the lightweight variant, and specifically profile and test the lightweight variant against realistic low end device and network constraints rather than assuming it will simply perform better by default.
I would use a standard framework like Hilt to manage dependency graphs consistently across modules, define clear scoping so dependencies live at the appropriate lifecycle level, whether application, activity, or a custom feature scope, and avoid manual dependency wiring that becomes unmanageable as the module count grows.
I would look at signals like how often changes in one feature unexpectedly break another, how long it takes new engineers to become productive, and how build and test times are trending, and use that evidence to decide whether stronger modularization or clearer architectural boundaries are needed.
I would favor a larger base of fast unit tests for business logic in ViewModels and repositories, a moderate layer of integration tests for critical flows, and a smaller set of UI or end to end tests reserved for the most business critical user journeys, since UI tests are the slowest and most brittle to maintain.
I would migrate incrementally, module by module or feature by feature, rather than attempting a full rewrite, prioritize the areas with the highest development activity so the team benefits from modern tooling sooner, and make sure Java and Kotlin interoperate cleanly throughout the transition period.
I would introduce a repository layer that abstracts away the specific data sources behind a clean interface the rest of the app depends on, define a clear source of truth and synchronization strategy between the sources, and keep the decision logic about which source to use out of the UI layer entirely.
I would build a shared design system module with reusable, well documented composables or views that teams are expected to use rather than building custom UI from scratch, and set up a lightweight review process for proposed additions to the shared system so it doesn't grow unchecked or inconsistently.
I would establish automated performance benchmarks for key metrics like startup time and frame rendering that run as part of the CI pipeline, set thresholds that flag meaningful regressions before a release ships, and track performance trends over time rather than only checking it reactively when users complain.
I would isolate the SDK's usage behind an internal abstraction layer if it isn't already, work with the vendor or check for a version update that addresses the issue, and evaluate a fallback or feature flag to disable the affected functionality quickly if the crashes are severe enough to warrant it before a proper fix ships.
8-10 Years
I would define a small set of shared, non negotiable principles like separation of business logic from UI and consistent dependency injection practices, publish reference implementations teams can build from, and allow flexibility in the specific patterns beyond that baseline rather than mandating one rigid architecture for every team.
I would base the decision on actual pain points like build time degradation and team coordination friction rather than module count as a goal in itself, and pilot modularization on a clearly bounded feature area before committing to a full scale restructuring of the codebase.
I would base the minimum supported version on actual usage data from the app's current user base rather than an arbitrary cutoff, weigh the engineering cost of supporting older versions against how small that user segment has become, and revisit the policy periodically as the distribution shifts.
I would assess which is currently posing the greater risk to velocity and stability, since a codebase accumulating too much debt eventually slows every future feature, and generally advocate for dedicated, protected time for debt reduction rather than letting it always lose out to feature pressure.
I would require a review process that checks a library's maintenance status, size impact on the app, and any permissions or data collection it introduces, maintain an approved list to avoid teams independently pulling in overlapping or risky libraries, and periodically audit existing dependencies for ones that have since become unmaintained.
I would set measurable targets per app based on current baselines, prioritize fixes by user impact rather than just crash count, and build accountability into each team's roadmap so stability work isn't treated as optional compared to feature delivery.
I would evaluate new capabilities against genuine current pain points rather than adopting everything immediately, pilot promising ones with a single team before recommending organization wide adoption, and weigh the migration cost against the concrete benefit for capabilities that would require touching a large amount of existing code.
I would define measurable targets tied to real user experience data and business impact rather than arbitrary numbers, build automated checks into each team's CI pipeline that flag regressions before release, and treat repeated budget violations as a conversation about the team's practices rather than only a technical alert.
I would fund it as a shared service with cost justified by the duplicated effort and inconsistency it prevents across product teams, and periodically reassess its scope and staffing against how much the organization's Android footprint has actually grown.
I would establish a standing process for tracking upcoming Android platform changes well ahead of enforcement deadlines, require every app to have an owner accountable for compliance, and prioritize apps handling the most sensitive data or largest user bases first when remediation work needs to be sequenced.
I would build core, ongoing product development capability in-house given how central it is to the business, and reserve external contractors for specialized, time bound needs like a major platform migration, to avoid ongoing premium costs for steady state work that's better owned internally.
I would define a service level expectation tied to the severity of the vulnerability, require a tested rollout process so patching doesn't itself introduce instability, and track compliance across apps so patching doesn't quietly slip for lower visibility or less actively maintained apps.
I would evaluate each new initiative against its specific requirements, like how much it depends on deep platform integration or native performance, rather than mandating one approach organization wide, and keep native Android expertise strong for the products where it genuinely provides a meaningful advantage.
I would set a baseline required quality gate, like passing automated tests and a stability check, that applies to every team regardless of cadence, while allowing individual teams flexibility in how frequently they release beyond that shared minimum bar.
10+ Years
I would walk through a real profiling session together on one of their own features, showing concretely where time is being spent, and build the habit of checking frame timing and main thread work as part of their normal development process rather than only fixing it reactively when a user reports lag.
I would anticipate that practices fine at a small scale, like a single monolithic module or informal architecture decisions, break down with growth, and proactively invest in shared platform infrastructure, modularization, and clear architectural standards before they become urgent pain points blocking team velocity.
I would translate the technical issues into business terms like user retention or store rating impact tied to crash rates and slow load times, using concrete data from the app's own metrics, and present a phased investment plan with measurable milestones rather than asking for an open ended commitment.
I would ground the discussion in the team's actual constraints, like how much of the existing codebase would realistically need rewriting and the team's familiarity with each approach, pilot the migration on a bounded new feature to gather real evidence, and make the final call myself if the debate isn't converging given the cost of prolonged indecision.
I would have them quantify the actual scope and user impact of the problem before proposing a solution, since I've seen engineers reach for large architectural changes for problems a targeted fix would resolve, and coach them to weigh the risk and cost of broader change against the value it would actually unlock.
I would push for that logic and the reasoning behind its design to be documented, deliberately rotate ownership and code review responsibilities across a wider group of engineers, and treat concentrated critical knowledge as an ongoing risk to actively manage rather than something addressed only once someone leaves.
I would coach them to frame the recommendation around a specific pain point the team already feels, like difficulty testing existing code, rather than presenting it as an abstract best practice, and have them build credibility through a small, concrete win before pushing for broader adoption.
I would look for strong fundamentals in Android's core concepts and general software architecture rather than requiring deep familiarity with the organization's specific conventions on day one, and pair new hires with an experienced engineer on real feature work so the conventions are learned through practice rather than only documentation.
I would invest ahead of the demand curve in self service tooling and clear documentation so routine requests don't all require direct platform team involvement, plan staffing growth proactively rather than reactively, and periodically reassess whether the team's structure still matches the organization's current scale.
I would present a phased plan grounded in what's realistically achievable per quarter given team capacity, be explicit about dependencies like feature freeze windows needed for high risk migration steps, and avoid overpromising a fast, all encompassing migration that would set the initiative up to look like it's failing.
I would assess which currently poses the greatest risk to the product's stability and the team's ability to deliver future features efficiently, and generally advocate for protecting meaningful, consistent investment in debt reduction and platform health rather than letting it always lose out to feature pressure in the moment.
I would make raising these issues a normal, rewarded part of the process rather than something reflecting poorly on the original author, allocate real time in the roadmap to address flagged issues rather than treating it as something to fit around feature work, and follow through visibly so the team trusts that flagging problems actually leads to improvement.
I would start a structured knowledge transfer well ahead of the transition, involve less experienced engineers in real architectural decisions under the architect's guidance rather than relying on passive documentation, and identify one or more successors who get genuine ownership of key parts of the codebase before the transition is complete.
I would define a small set of non negotiable organization wide standards, like security baselines and shared design system usage, while leaving implementation details and feature specific architecture choices to individual teams who understand their own product's needs best, revisiting where that balance sits as the organization evolves.




