Android App Development Interview Questions for Freshers
40 questions with answers for candidates with Freshers — 21 easy, 19 medium.
What interviewers expect: freshers
Fresher interviews test Kotlin basics, OOP, the Activity lifecycle, simple Compose UI and how you call an API. Expect a short coding round, questions about your college or personal projects, and why you chose Android. Interviewers want proof that you can build a working app on your own, so be ready to explain every part of your project.
This set is weighted towards Kotlin Fundamentals (8), Testing, Performance and Play Store (8), Android Components and Lifecycle (7), App Architecture, MVVM and Hilt (5).
Kotlin fundamentals and OOP Activity lifecycle and intents Basic Compose layouts and state One complete project with API and storage
Solved at this levelStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
✓ 3 questions free • Unlock the rest in seconds
01
Write a use case that combines cart items and a coupon into a final total.
A BroadcastReceiver responds to broadcast intents. Since Android 8, most implicit broadcasts cannot be received by receivers declared in the manifest; you register them at runtime with registerReceiver while the app is running. A few exemptions exist, like BOOT_COMPLETED and locale change. Since Android 14, runtime receivers must specify RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED. onReceive runs on the main thread, so keep it short or use goAsync.
03
What are higher-order functions and lambdas in Kotlin?
A higher-order function takes a function as a parameter or returns one. A lambda is an anonymous function literal like { x: Int -> x * 2 }. Collection operations such as map, filter and forEach are higher-order functions. In Android you see them in click listeners, Compose callbacks like onClick = { } and coroutine builders. If the last parameter is a function, the lambda can be written outside the parentheses, known as trailing lambda syntax.
04
How do you pass data between screens and what is the size limit?
Traditionally through Intent extras or Fragment arguments as a Bundle with primitives, Parcelable or Serializable objects. Bundles go through Binder transactions, which have a shared limit of about 1 MB, so large data causes TransactionTooLargeException. Pass an ID instead and load the data from a repository or database on the next screen. With Navigation, use type-safe route arguments and a shared ViewModel only when screens truly share state.
05
Explain the steps to publish an app on the Play Store.
Create a developer account, then an app in Play Console. Complete the store listing, content rating, data safety form, target audience, privacy policy and permissions declarations. Build a signed release AAB with a higher versionCode, upload it to internal testing first, then closed or open testing, and finally production with a staged rollout. New personal accounts must run a closed test with at least 12 testers for 14 days before production.
Activities provide a screen the user interacts with. Services run work without a UI, such as music playback. Broadcast receivers respond to system or app-wide events like boot completed or connectivity change. Content providers share structured data between apps, such as contacts. Each component is an entry point the system can start, and most must be declared in AndroidManifest.xml with appropriate intent filters and permissions.
07
Write a manifest entry for a deep link that opens a product screen.
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="shop.example.com"
android:pathPrefix="/product" />
</intent-filter>
</activity>
<!-- autoVerify plus assetlinks.json on the domain makes it an App Link -->
08
How do you check network connectivity in modern Android?
Use ConnectivityManager with registerDefaultNetworkCallback and NetworkCapabilities to check NET_CAPABILITY_INTERNET and VALIDATED, and expose it as a Flow with callbackFlow. NetworkInfo and the CONNECTIVITY_ACTION broadcast are deprecated. Remember that being connected does not guarantee a working server, so still handle request failures. Use the status to show an offline banner and pause retries, not to block every request.
09
What is an Android App Bundle and why does Play require it?
An App Bundle (.aab) is a publishing format containing all compiled code and resources. The Play Store generates optimised APKs for each device configuration, delivering only the needed screen density, CPU architecture and language resources, which reduces download size. Since August 2021, new apps on Play must use AAB with Play App Signing, where the store holds the app signing key and you sign uploads with an upload key.
10
How do you explain a technical limitation to a non-technical product manager?
I focus on user impact and options rather than jargon. For example, when asked for background tracking every second, I explained that Android limits background work to save battery, so the app would need a visible notification and stricter Play review. I offered two options with trade-offs and a recommendation. Using a simple diagram helped, and the PM chose the option that met the business need with fewer risks.
11
How do you handle a code review comment you disagree with?
I first assume the reviewer has a reason and ask questions to understand it. If I still disagree, I explain my reasoning with evidence, such as documentation, a benchmark or a test, and suggest a short call if comments go back and forth. If it is a matter of preference, I follow the team convention. The goal is the best code for the team, not winning the argument.
12
How do default and named arguments reduce the need for overloads?
Kotlin functions can define default values, such as fun showToast(msg: String, long: Boolean = false), so callers skip arguments they do not need. Named arguments, like showToast(msg = "Saved", long = true), make calls readable and let you change argument order. Together they replace telescoping constructors and builder patterns in many cases. For Java callers, add @JvmOverloads so overloads are generated automatically.
13
Write a LazyColumn that shows a list of products with keys and a click handler.
A suspend function returns a single value once. A Flow is a cold asynchronous stream that emits multiple values over time, like database updates, location changes or search results. Cold means the code inside flow { } runs only when collected, and runs again for each collector. Room, DataStore and many libraries expose Flow so the UI automatically updates when underlying data changes.
15
How do you collect a ViewModel StateFlow in a composable?
Use val state by viewModel.uiState.collectAsStateWithLifecycle() from lifecycle-runtime-compose. It collects only while the lifecycle is at least STARTED, saving resources in the background, unlike collectAsState which keeps collecting. Pass the resulting state and callbacks to a stateless screen composable, which keeps the screen previewable and testable without a ViewModel. Obtain the ViewModel with hiltViewModel() or viewModel() at the route level.
16
You need to cache API responses so the home screen opens instantly. What approach do you take?
Store the response in Room, or a file for a single blob, and have the screen observe the cached data immediately while a refresh runs in the background, known as stale-while-revalidate. Store a timestamp to decide when cache is too old. HTTP caching with OkHttp Cache can also help for GET requests with proper cache headers. Show cached content first, then update smoothly when fresh data arrives.
network_security_config.xml, referenced from the manifest, controls TLS behaviour without code. Since Android 9, cleartext HTTP is blocked by default; you can allow it for specific debug domains. You can trust user-added CAs only in debug builds for tools like Charles or proxies, and define certificate pins with expiry. Keeping cleartext disabled in production is an important security baseline.
18
How do you keep up with changes in Kotlin and Android?
I follow the Android Developers blog and release notes for Jetpack libraries, read the Kotlin release notes for each version, and watch sessions from the main yearly Android conferences. I try new APIs in a small side project before proposing them at work, and I read pull requests from experienced colleagues. Once a month I review deprecation warnings in our project so upgrades stay small and planned.
launch starts a coroutine for work that returns no result and gives back a Job you can cancel or join. async returns a Deferred<T>, and you call await() to get the result. Use async to run independent tasks in parallel, such as fetching profile and orders together, then awaiting both. Exceptions differ: launch propagates them to the parent immediately, while async holds them until await, though in structured concurrency the parent still gets cancelled.
20
Why should a ViewModel never hold a reference to an Activity, Fragment or View?
A ViewModel outlives the Activity during configuration changes. If it holds the old Activity or a view, that Activity cannot be garbage collected after rotation, causing a memory leak and possibly crashes when updating a dead view. Expose state for the UI to observe instead. If you need a Context for resources, inject the Application context or better, move that work into a repository or use resource IDs in state.
21
What is targetSdkVersion and why does Play enforce updates?
targetSdkVersion tells Android which platform behaviour your app was tested against; the system applies newer behaviour changes only when you target that level. The Play Store requires new apps and updates to target a recent API level, usually within one year of a release, so users benefit from security and privacy changes. minSdk sets the oldest supported version and compileSdk the API you compile against.
22
Write a function that safely parses a string to an Int and returns a default on failure.
fun String?.toIntOrDefault(default: Int = 0): Int =
this?.trim()?.toIntOrNull() ?: default
// Usage
val qty = input.text.toString().toIntOrDefault(1)
val age = null.toIntOrDefault() // 0
In unidirectional data flow, state flows down from the ViewModel to the UI, and events flow up from the UI to the ViewModel. The UI never changes state directly; it calls functions like onAddToCart(id), the ViewModel updates an immutable state object, and the UI re-renders. This makes state changes predictable, traceable and testable, and it is the model that Jetpack Compose is built around.
24
What is the difference between == and === in Kotlin?
== checks structural equality and calls equals() under the hood, handling nulls safely. === checks referential equality, meaning both references point to the same object in memory. For two data class instances with the same values, == returns true but === returns false unless they are the same instance. For primitive-like types such as Int, === may behave unexpectedly due to boxing, so == is the normal choice.
25
Write a sealed interface for a screen state and handle it with when.
sealed interface UiState {
data object Loading : UiState
data class Success(val items: List<String>) : UiState
data class Error(val message: String) : UiState
}
fun render(state: UiState) = when (state) {
UiState.Loading -> showProgress()
is UiState.Success -> showList(state.items)
is UiState.Error -> showError(state.message)
}
26
The crash-free rate dropped after a release only on Android 15 devices. How do you respond?
Halt the staged rollout immediately. Filter Crashlytics or Play vitals by OS version to find the top crash, then check Android 15 behaviour changes such as edge-to-edge enforcement, foreground service rules or new restrictions affecting your target SDK. Reproduce on an Android 15 emulator, fix, add a test, and resume rollout with the hotfix. Afterward, add Android 15 devices to the regular test matrix.
27
Write a delegated property that logs whenever a value changes.
import kotlin.properties.Delegates
class Settings {
var theme: String by Delegates.observable("light") { prop, old, new ->
println("${prop.name} changed from $old to $new")
}
}
// Use Delegates.vetoable if you need to reject a change
// by returning false from the lambda.
28
How do you build a single-activity app with the Navigation component?
Keep one Activity hosting a NavHost, and represent each screen as a Compose destination or Fragment. Define routes in a navigation graph, preferably with type-safe routes using Kotlin serialization in Navigation 2.8 and later. Use nested graphs for flows like login or checkout, pop the back stack with popUpTo when finishing a flow, and handle deep links on destinations. This simplifies shared transitions and state handling.
29
How do you implement theming with Material 3 in Compose?
Wrap the app in a MaterialTheme with a ColorScheme, Typography and Shapes. Use lightColorScheme and darkColorScheme, pick based on isSystemInDarkTheme(), and use dynamicLightColorScheme or dynamicDarkColorScheme on Android 12 and above for Material You colours. Components read MaterialTheme.colorScheme.primary and similar roles, so avoid hardcoding colours. Extend the theme with a custom CompositionLocal for brand-specific tokens.
30
What is a coroutine and how is it different from a thread?
A coroutine is a suspendable computation that can pause at suspension points without blocking the thread it runs on. Thousands of coroutines can share a small thread pool because suspended coroutines do not hold a thread. Threads are managed by the OS, are heavier in memory and context switching. On Android, coroutines let you write asynchronous code like network calls in a sequential style, without callbacks, while keeping the main thread free.
31
What is a repository and why is it the single source of truth?
A repository hides where data comes from and gives the rest of the app one API, such as getProducts(): Flow<List<Product>>. With an offline-first design, the repository reads from Room and refreshes from the network in the background, writing results to the database. The UI always observes the database, so it is the single source of truth. This avoids inconsistent copies of data across screens.
32
What conflict strategies does Room offer for inserts?
@Insert(onConflict = ...) supports REPLACE, which deletes the old row and inserts the new one; IGNORE, which skips the insert; ABORT, the default, which rolls back the transaction; and others. REPLACE can trigger cascading deletes on foreign keys because it deletes first. @Upsert, added in Room 2.5, inserts or updates without deleting, making it safer for syncing server data into local tables.
33
What is the difference between lateinit and by lazy?
lateinit works only with var and non-primitive, non-null types; you promise to assign it before use, and accessing it early throws UninitializedPropertyAccessException. by lazy works with val; the initialiser runs once on first access and the result is cached, thread-safe by default. Use lateinit for values injected or set in lifecycle callbacks, such as a binding in onCreate, and lazy for expensive values computed on demand.
On every pull request, run lint, ktlint or detekt, unit tests and a debug build in a CI service like GitHub Actions or Bitrise, with Gradle caching. On merge to main, build a signed release AAB using secrets, run instrumented tests on emulators or a device farm, and upload to the Play internal track with Gradle Play Publisher or fastlane. Promote to production manually after QA with a staged rollout.
onCreate runs once to set up the UI and state. onStart makes the activity visible, onResume makes it interactive in the foreground. onPause runs when it loses focus, onStop when it is no longer visible, and onDestroy before it is removed. Rotation by default destroys and recreates the activity. Release resources like camera in onPause or onStop, and save transient UI state with ViewModel and SavedStateHandle.
36
Tell me about a time you worked closely with a backend team to solve a problem.
Situation: our feed took four seconds to load because the app made six API calls. Task: reduce load time. Action: I measured each call with network profiling, shared a timeline with the backend team, and we agreed on one aggregated endpoint with only the fields the screen used, plus pagination. I updated the client and added caching. Result: load time dropped to under one second and both teams reused the approach.
37
Write a Gradle configuration for release signing and minification using environment variables.
A sealed class restricts its subclasses to a known set defined in the same package and module. The compiler knows every subtype, so a when expression over it can be exhaustive without an else branch. On Android it is commonly used to model UI state such as Loading, Success(data) and Error(message), or one-time events. Adding a new subtype causes compile errors wherever handling is missing, which prevents forgotten cases.
SavedStateHandle is a key-value map available to a ViewModel that is saved into the instance state Bundle, so it survives process death as well as configuration changes. Navigation arguments are also placed in it automatically. Use it for small, essential UI state like a search query, selected filter or the ID of the item being edited. Do not put large lists in it; reload those from the repository.
40
What types of tests do you write for an Android app?
Local unit tests on the JVM cover ViewModels, use cases, repositories and mappers with JUnit, fakes and coroutine test tools; they are fast and most numerous. Instrumented tests run on a device or emulator for Room, Compose UI and integration flows. End-to-end UI tests check critical journeys like login and checkout. Screenshot tests catch visual regressions. Follow the testing pyramid: many unit tests, fewer UI tests.
Frequently asked questions
What is asked in Android App Development interviews for Freshers?
Fresher interviews test Kotlin basics, OOP, the Activity lifecycle, simple Compose UI and how you call an API. Expect a short coding round, questions about your college or personal projects, and why you chose Android. Interviewers want proof that you can build a working app on your own, so be ready to explain every part of your project.
How many questions should I practise before a Android App Development interview?
Work through all 40 questions here, then the company-wise sets for the employers you are targeting. Quality matters more than count: be able to explain why each answer is right.
Which topics matter most for Freshers?
Focus first on Kotlin fundamentals and OOP, Activity lifecycle and intents, Basic Compose layouts and state, One complete project with API and storage.