Interview questions · free

Android Developer interview questions and answers

29 questions Android Developer interviews in India ask, grouped by the 7 skills they test, with a short model answer for each. Then the HR round every job has. Try each one out loud before you open the answer.

  • 29 questions
  • 7 skills
  • 15 for freshers
  • Updated 30 Oct 2026

First mock interview free: 3 questions, a score and feedback on each · No card needed

Answer out loud first. Read the question, say your answer as you would in the room, then open the model answer and compare. Interviewers ask follow-ups, so learn the reasoning, not the words.

Mobile platform · Core skill

App lifecycle

Most Android crashes and lost-data bugs come from the lifecycle, so interviewers check that you know what Android does to your screens when users rotate, switch apps or come back later.

Explain the Activity lifecycle. Which callbacks run when a user opens the app, presses Home, and then comes back?Fresher

The main callbacks are onCreate, onStart, onResume, onPause, onStop, onRestart and onDestroy. Opening the app runs onCreate (set up the UI), onStart (now visible) and onResume (in the foreground and taking input). Pressing Home runs onPause and then onStop: the Activity is hidden but still in memory. Coming back runs onRestart, onStart and onResume. Pressing Back finishes the Activity with onPause, onStop and onDestroy (since Android 12, Back on the app's first screen only moves it to the background).

Say what you do in each: start a camera preview or location updates in onStart or onResume, release them in onPause or onStop, and never rely on onDestroy being called, because the system can kill a background process without it.

What happens to an Activity when the user rotates the phone? How do you make sure the data on screen isn't lost?Fresher

Rotation is a configuration change, and by default Android destroys the Activity and creates it again so it can load resources for the new orientation. Anything stored only in the Activity's fields is lost.

Keep screen data in a ViewModel, which survives configuration changes, so the new Activity gets the same ViewModel and doesn't reload from the network. Small UI state, like the text in a search box or a selected tab, goes in saved instance state: onSaveInstanceState, SavedStateHandle in the ViewModel, or rememberSaveable in Compose. Mention that adding android:configChanges to stop the recreation is a last resort, because you then handle every resource change yourself.

In a single-activity app, how do you handle navigation between screens and pass data from one screen to the next?1-6 years

I use the Navigation component: a NavHost holds the screens, a NavController moves between them, and the back stack is managed for me, including the system Back button and deep links. In Compose that's Navigation Compose with type-safe routes; with fragments, a nav graph and Safe Args.

I pass small values, usually an ID, not whole objects. The next screen's ViewModel reads the ID from its SavedStateHandle and loads the data from the repository, so it survives process death too. To clear screens from the back stack, for example the login screen after signing in, I use popUpTo with inclusive. To return a result, I set it on the previous back stack entry's SavedStateHandle.

A user fills half a form, switches to another app for an hour, comes back, and the form is empty or the app crashes. What happened and how do you fix it?1-6 years

Most likely the system killed the app's process in the background to free memory. When the user returns, Android recreates the Activity and restores the back stack, but the ViewModel, singletons and static fields start fresh. So the form is empty, and code that assumed something was already loaded, such as a lateinit property, crashes.

The fix is to keep the form's values in SavedStateHandle or rememberSaveable, which survive process death, and save longer drafts to Room or DataStore. Never assume in-memory state from an earlier screen still exists. I reproduce it with the Don't keep activities developer option, or by sending the app to the background and killing it with adb shell am kill.

Mobile platform · Core skill

UI and layouts

Android developers spend much of their day building screens, so expect questions on XML layouts, RecyclerView and Jetpack Compose, and on screens that work on every phone and tablet.

Why is ConstraintLayout preferred over nesting LinearLayouts? What are constraints?Fresher

A constraint ties a view's edge to another view or to the parent, for example the button's top to the bottom of the text field, with a margin. Because you can position views relative to each other and to the parent in one level, ConstraintLayout replaces deep nesting of LinearLayouts and RelativeLayouts with a flat hierarchy.

That matters for performance: each layout level has to be measured and laid out, and nested LinearLayouts with layout_weight measure their children more than once. A flat layout is faster and easier to change. Mention chains for spreading views evenly, guidelines for percentage positions, and 0dp (match constraint) for a view that fills the space between its constraints.

How does RecyclerView work? Why is it better than creating a view for every item?Fresher

RecyclerView creates only enough item views to fill the screen, plus a few spare. As the user scrolls, a view that leaves the screen is recycled: the adapter binds the new item's data into it instead of inflating a new one. The adapter creates ViewHolders in onCreateViewHolder and fills them in onBindViewHolder, and the LayoutManager decides the arrangement: vertical list, grid or staggered grid.

So a list of 10,000 items uses a few dozen views, which saves memory and keeps scrolling smooth. For updates, use ListAdapter with DiffUtil, which works out exactly which items changed and animates them, instead of notifyDataSetChanged, which rebinds everything.

A LazyColumn in your Jetpack Compose screen stutters while scrolling. What would you check?1-6 years

First I check that I'm testing a release build, because debug Compose is much slower. Then I look for unnecessary recomposition with the Layout Inspector's recomposition counts. Common causes: no stable key in items(), so items are recomposed or lose state when the list changes; unstable parameters, such as a plain List or a class from another module, which stop Compose from skipping items; and heavy work inside a composable, like sorting, formatting dates or decoding images on every recomposition.

The fixes are keys from item IDs, immutable UI models, remember or derivedStateOf for computed values, moving work to the ViewModel, and an image library that loads at the right size. Baseline profiles also improve scrolling and startup.

Your app looks fine on your phone but breaks on a small phone, a tablet and with large font sizes. How do you build screens that adapt?1-6 years

Use dp for sizes and sp for text, and avoid fixed heights for anything with text, so it can grow when the user increases the font size. Let views fill available space with constraints, weights or Compose modifiers like fillMaxWidth and weight instead of hard-coded widths, and make long content scrollable.

For tablets and foldables, use window size classes to switch layouts: one pane on a phone, list and detail side by side on a wide screen. With XML, resource qualifiers such as layout-sw600dp do the same. Test with the largest font and display size settings, landscape mode and resizable emulators; mention that a cut-off button with large fonts is a common accessibility bug.

Language · Core skill

Kotlin / Swift / Dart

Kotlin is the language of modern Android, and interviewers check that you use its features, null safety, data classes and coroutines, rather than writing Java in Kotlin syntax.

How does Kotlin's null safety work? Explain ?., ?: and !!.Fresher

In Kotlin a type can't hold null unless you mark it nullable with a question mark: String can never be null, String? can. The compiler then forces you to handle the null case before using it. The safe call user?.name returns null instead of crashing if user is null. The Elvis operator gives a default: user?.name ?: "Guest". The not-null assertion user!!.name tells the compiler you're sure, and throws a NullPointerException if you're wrong.

So avoid !! in real code. Mention that values coming from Java code have platform types, where Kotlin can't know whether they're nullable, so nulls can still sneak in there.

What is a data class in Kotlin? What do you get for free, and when would you use a sealed class instead?Fresher

A data class is meant to hold data. For the properties in its primary constructor, Kotlin generates equals, hashCode, toString, copy and componentN functions, so two objects with the same values are equal and you can write val updated = user.copy(name = "Ravi"). Properties declared in the class body are left out of those functions.

A sealed class or interface is for a fixed set of types, such as a screen state that is Loading, Success with data, or Error with a message. Because the compiler knows every subtype, a when expression over it must cover all of them, so adding a new state shows you every place to update. Data classes are often the subtypes of a sealed class.

Explain Kotlin's scope functions: let, apply, also and run. When would you use each?Fresher

They all run a lambda on an object; they differ in how you refer to the object (it or this) and what they return. let uses it and returns the lambda's result, most often with a safe call: user?.let { show(it) } runs only when user isn't null. apply uses this and returns the object itself, so it suits setting up an object: Intent(...).apply { putExtra(...) }. also uses it and returns the object, for side effects like logging. run uses this and returns the result, for computing something from an object.

Interviewers like a sensible rule: use them where they make code clearer, and don't nest several, because it becomes hard to tell what it and this refer to.

What are coroutines? Explain launch versus async, dispatchers, and structured concurrency in an Android app.1-6 years

Coroutines let you write asynchronous code in a sequential style. A suspend function can pause without blocking the thread, so a network call doesn't freeze the UI. launch starts a coroutine that returns a Job and no result; async returns a Deferred whose result you get with await, which is useful for running two calls in parallel. Dispatchers choose the threads: Main for UI, IO for network and disk, Default for CPU work.

Structured concurrency means every coroutine runs in a scope, and cancelling the scope cancels its children. viewModelScope is cancelled when the ViewModel is cleared, so requests stop when the user leaves. Avoid GlobalScope, and remember that an exception in a child cancels its siblings unless you use a SupervisorJob.

Networking

APIs and networking

Almost every Android app talks to a backend, so expect to explain how you call APIs with Retrofit, handle failures on flaky mobile networks and keep users signed in.

How do you call a REST API in Android using Retrofit?Fresher

Add the INTERNET permission, then describe the API as a Kotlin interface: annotate each function with the HTTP method and path, for example @GET("users/{id}") suspend fun getUser(@Path("id") id: String): User. Build a Retrofit instance with the base URL, an OkHttp client and a JSON converter such as Moshi, Gson or kotlinx.serialization, and let Retrofit create the implementation.

Call the suspend function from a coroutine, usually in the repository and started from viewModelScope. Retrofit runs suspend calls off the main thread, so you don't block the UI. Mention @Query for query parameters and @Body for a POST body, and keep the Retrofit instance as a single shared object, usually provided through Hilt.

How do you handle API errors in an Android app: no internet, timeouts, server errors and unexpected JSON?1-6 years

I separate the kinds of failure. With suspend Retrofit functions, an IOException means the request didn't complete: no connection or a timeout. An HttpException means the server answered with an error code, which I read to show the right message, such as 401 sign in again or 500 try later. A parsing exception means the JSON didn't match the model. The repository catches these and returns a Result or a sealed type, so the ViewModel shows an error state with a Retry button instead of crashing.

I also set sensible connect and read timeouts in OkHttp, retry only safe requests, and log parsing errors, because they usually mean the API changed without notice.

How do you add an auth token to every request and refresh it when it expires?1-6 years

An OkHttp Interceptor adds the Authorization header with the current access token to each request, so no API function has to. For expiry, OkHttp's Authenticator is called when the server returns 401: it calls the refresh endpoint, saves the new tokens and retries the original request with the new token. If the refresh fails, it returns null and the app signs the user out.

The tricky part is several requests failing at once: synchronise the refresh so only one call refreshes, and the others reuse the new token. Store tokens in encrypted storage rather than plain SharedPreferences, never log them, and keep the refresh call on a client without the Authenticator to avoid a loop.

Reading an answer isn't the same as giving one

In a mock interview you answer new Android Developer questions out loud or typed, and every answer is scored, with what to fix and a stronger answer.

Try it free

Mobile platform

Local storage

Apps need to work with poor or no connectivity and remember settings, so interviewers ask which Android storage to choose and how you cache data safely.

When would you use SharedPreferences, DataStore or Room?Fresher

SharedPreferences and DataStore are for small key-value data, like a theme choice or whether onboarding was seen. DataStore is the modern replacement for SharedPreferences: it works asynchronously with coroutines and Flow, so it never blocks the main thread, and handles errors better. Preferences DataStore stores key-value pairs; Proto DataStore stores a typed object.

Room is for structured data you query, such as a list of orders or cached products. It's a layer over SQLite that checks your SQL queries at compile time and can return a Flow, so the UI updates when the data changes. Don't put large lists in preferences, and don't store passwords or tokens unencrypted in either.

What are the main parts of Room? What happens when you change a table in an app that's already released?Fresher

Room has three parts: an Entity is a data class that defines a table, a DAO is an interface with annotated methods for queries, inserts, updates and deletes, and the Database class lists the entities and provides the DAOs. DAO methods can be suspend functions or return Flow, and Room doesn't allow queries on the main thread by default.

If you change a table, for example add a column, you must increase the database version and provide a migration, either a Migration with the ALTER TABLE SQL or an auto-migration. Without one, the app crashes on update, or loses users' data if you used fallbackToDestructiveMigration. Test migrations with Room's MigrationTestHelper.

How would you design an offline-first screen, such as a product list that works without internet?1-6 years

I make the local database the single source of truth. The UI observes a Flow from a Room DAO and shows whatever is stored, immediately, even offline. The repository refreshes from the network in the background, writes the results to Room, and the UI updates automatically because it's watching the table. If the refresh fails, the user still sees cached data with a small message, not an empty screen.

I store a last-updated time to decide when data is stale. For changes made offline, like adding to a cart, I save them locally with a pending flag and send them with WorkManager when the network returns, with a constraint and retries. Mention how you'd handle conflicts if the server data changed meanwhile.

App architecture

Architecture patterns

Teams want code that survives new features and new developers, so interviewers check that you can structure an app with MVVM, clean state handling and dependency injection.

Explain MVVM as you would use it in an Android app.Fresher

The View, an Activity, Fragment or composable, only draws the state and passes user actions to the ViewModel. The ViewModel holds the screen's state, usually as a StateFlow, survives configuration changes, and calls a repository for data. The repository decides whether data comes from the network, the Room database or both, so the ViewModel doesn't care. Larger apps add use cases between the ViewModel and the repository for business rules, and split features into separate Gradle modules.

The benefits are a clear separation of concerns, a UI that doesn't lose data on rotation, and ViewModels you can unit test with a fake repository. Mention that the ViewModel must never hold a reference to an Activity or View, because that leaks memory.

How do you expose screen state from a ViewModel, and how do you handle one-time events like a snackbar or navigation?1-6 years

I expose one immutable UiState data class through a StateFlow, for example with isLoading, items and errorMessage, and update it with copy, so the screen always renders from a single, consistent state. The UI collects it in a lifecycle-aware way: collectAsStateWithLifecycle in Compose, or repeatOnLifecycle(STARTED) with views, so it stops collecting in the background.

For one-time events, the current guidance is to model them as state too: put the message in UiState, and when the UI has shown it, call a ViewModel function that clears it. That avoids events lost during rotation. Some teams use a Channel received as a Flow; it works, but events can be missed if nobody is collecting at that moment.

What is dependency injection, and how do you use Hilt in an Android project?1-6 years

Dependency injection means a class receives what it needs from outside instead of creating it, so you can swap a real repository for a fake in tests. Hilt, built on Dagger, generates that wiring at compile time. You annotate the Application class with @HiltAndroidApp, Activities and Fragments with @AndroidEntryPoint, and ViewModels with @HiltViewModel and an @Inject constructor.

Classes you own get @Inject constructors; for interfaces and third-party objects like Retrofit, you write a @Module with @Binds or @Provides, installed in a component such as SingletonComponent. Scopes like @Singleton control how long an instance lives. Common mistakes are scoping everything as a singleton and putting Context-heavy objects where they leak.

Quality

Testing

Android apps run on thousands of device models, so teams value developers who write unit and UI tests and know how to test on real devices before a Play Store release.

What is the difference between the test and androidTest folders in an Android project?Fresher

Code in src/test is local unit tests: they run on your computer's JVM, so they're fast, and they test logic without an Android device, such as ViewModels, repositories with fakes, and utility functions. Code in src/androidTest is instrumented tests: they run on an emulator or a real device, so they can use real Android components, such as Room databases, Espresso or Compose UI tests and the Context.

Most tests should be fast local unit tests, with fewer instrumented tests for the UI and integration. Robolectric is a middle option that runs some Android code on the JVM. Mention that a healthy project runs unit tests on every commit in CI.

How would you unit test a ViewModel that loads data from a repository using coroutines?1-6 years

I give the ViewModel a fake repository, a small class implementing the same interface that returns prepared data or throws an error, or a mock made with MockK or Mockito. Because viewModelScope uses Dispatchers.Main, which doesn't exist on the JVM, I replace it in tests with Dispatchers.setMain and a test dispatcher, usually through a JUnit rule.

The test runs inside runTest, which skips delays and controls when coroutines run. Then I trigger the action and assert the StateFlow's values: loading first, then the data, or an error state when the fake throws. The Turbine library makes checking a sequence of Flow values easy. Injecting dispatchers into the repository, rather than hard-coding Dispatchers.IO, keeps it testable too.

Your UI tests pass on your emulator but fail randomly in CI. How do you make them reliable, and how do you test on real devices?1-6 years

Flaky UI tests usually come from timing: the test checks the screen before data loads or an animation ends. Espresso and Compose tests wait for the main thread to be idle, but not for your own background work, so I use idling resources or test dispatchers, and fake the network rather than calling a real server. I disable animations on test devices, avoid fixed sleeps, and make each test independent, with its own data.

For devices, I run the important flows on a range of real phones, including a low-end one and older Android versions, using a device farm such as Firebase Test Lab. Before release, a staged rollout in the Play Console and the crash reports catch what testing missed.

Every job

HR and behavioural round

Android interviews end with an HR or managerial round that checks how you learn, ship and work with designers and backend teams. Have examples from apps you've actually built.

Tell me about yourself.Fresher

Keep it to about a minute, and make it about Android: who you are now, what you've built, and why this role. For example: "I'm a [degree] graduate from [college], and I've been building Android apps in Kotlin for [time]. My main project is [app], which [what it does] and uses [Jetpack Compose, Room, Retrofit]. I [published it on the Play Store / tested it with real users], and the hardest part was [problem you solved]. I'm looking for a role where I can work on apps used by many people and learn from experienced developers."

Have the app on your phone, ready to show if they ask.

Why do you want to be an Android developer rather than work on web or backend?Fresher

Give a real reason and show you know what the work involves. Good reasons: you like building something people use every day on their phone, you enjoy UI and user experience, and in India most users reach the internet through Android phones, often low-cost ones on slow networks, which makes performance and offline support interesting problems.

For example: "I built [app] for [people], and watching them use it on cheap phones taught me to care about app size and speed. I want to keep working on that." Don't criticise web or backend work; you may need to work with those teams, and some knowledge of APIs is a plus.

Tell me about a crash or serious bug that reached users after a release. What did you do?1-6 years

Use the STAR method and show calm ownership. "After a release, crash reports showed a spike on [Android version / device] (situation). I was responsible for the release (task). I halted the staged rollout in the Play Console, found from the stack trace that [cause, for example a permission change on newer Android versions], fixed it, added a test, and released a hotfix within [time] (action). Crashes went back to normal, and we added that device to our test list and started releasing to a small percentage first (result)."

Interviewers want to hear what changed in your process afterwards, not only the fix.

A designer gives you a screen that's hard to build and may be slow on low-end phones. How do you handle it?1-6 years

Show that you collaborate rather than refuse. Understand what the design is trying to achieve first, then explain the cost in concrete terms and offer options. For example: "The blurred animated background looks great, but on [low-end phone] it dropped frames when I prototyped it. I suggested a static gradient with the same feel, and showed both on the device. We kept the effect on newer phones and used the simpler version elsewhere."

Mention that you build a quick prototype or measure before arguing, and that you follow Material guidelines and Android conventions, such as Back behaviour, so the app feels native.

Android changes every year. How do you keep your skills up to date?Fresher

Name specific habits rather than "I read blogs". For example: "I follow the Android Developers blog and release notes, watch the Google I/O sessions on Android each year, and read the behaviour changes for each new Android version, because they affect permissions, background work and notifications. When something new comes out, like [a Jetpack library], I try it in a small side project before using it at work."

You can add that Google Play requires apps to target a recent Android version, so keeping up isn't optional. Mention one thing you learnt recently and used, as proof.

Free interview questions, roadmaps and mock interviews: https://myskillgrid.com/interview-questions/android-developer/

Ready to answer them for real?

Your first Android Developer mock interview is free: 3 questions, a score and feedback for each, and a stronger answer to learn from, in about 10 minutes.