Skip to content

Android App Development Interview Questions in Ahmedabad

36 practice questions with answers for Android App Development interviews in Ahmedabad.

Android App Development jobs in Ahmedabad

Ahmedabad and GIFT City have a growing market for IT services, fintech and product start-ups. Companies here value hands-on skills and the ability to work across tools, especially in smaller teams.

Below are 36 questions that match the mix of service, product and domain employers hiring junior android developers in Ahmedabad.

Solved for AhmedabadStart 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

How does Kotlin handle null safety?

Save to ▾
Show answer
Kotlin's type system separates nullable types (String?) from non-nullable types (String). The compiler stops you calling methods on a nullable value without a check. You use the safe call operator ?., the Elvis operator ?: for defaults, smart casts after null checks, or !! to force a value and risk a NullPointerException. This moves most null crashes from runtime to compile time, which is a major reason Android adopted Kotlin.
02

How do you handle push notifications with Firebase Cloud Messaging?

Save to ▾
Show answer
Extend FirebaseMessagingService, override onNewToken to send the token to your server, and onMessageReceived to handle data messages. Notification messages are shown automatically by the system when the app is in background; data messages are always delivered to your code. Request POST_NOTIFICATIONS on Android 13 and above, create channels, and keep onMessageReceived short, using WorkManager for longer work triggered by the push.
03

You need to cache API responses so the home screen opens instantly. What approach do you take?

Save to ▾
Show answer
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.
04

How do you implement theming with Material 3 in Compose?

Save to ▾
Show answer
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.
05

How do you share data between two screens in a checkout flow?

Save to ▾
Show answer
Options in order of preference: pass small IDs as navigation arguments and load the rest from a repository; store flow data in a repository scoped to the session; or use a ViewModel scoped to a nested navigation graph so all checkout screens share it and it is cleared when the flow ends. Avoid activity-scoped ViewModels holding everything, and avoid passing large objects through arguments.
06

The backend team changed a field from a number to a string and the app crashed for all users. How do you prevent this?

Save to ▾
Show answer
Short term, make parsing lenient for that field, for example with a custom serializer, and handle parse failures without crashing. Long term, agree on API contracts with versioning, use contract tests or a shared OpenAPI schema checked in CI, add ignoreUnknownKeys and default values in kotlinx.serialization, and use remote config or a minimum supported app version mechanism. Monitor parse errors as non-fatal events.
07

Users who reinstall the app lose all their settings. How can you restore them?

Save to ▾
Show answer
Android Auto Backup automatically backs up app data to the user's cloud backup account for apps targeting API 23 and above, unless disabled. Configure dataExtractionRules for Android 12 and above to include settings files and exclude tokens or caches. For important data like notes, sync to your own server tied to the user's account, since backup is not guaranteed. Test with adb shell bmgr commands.
08

What is a sealed class and when would you use it on Android?

Save to ▾
Show answer
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.
09

Your team is migrating a Java Android app to Kotlin. How would you plan it?

Save to ▾
Show answer
Kotlin and Java interoperate, so migrate gradually rather than all at once. Start with new features in Kotlin, then convert leaf classes like models and utilities, writing tests before converting. Add nullability annotations to Java code so Kotlin sees correct types. Review auto-converted code because it often overuses !!. Track progress per module and agree on style rules with ktlint or detekt so the codebase stays consistent.
10

Where should API keys go in an Android app?

Save to ▾
Show answer
Anything shipped in the APK can be extracted, so treat client-side keys as public. Keep them out of version control using local.properties or CI secrets injected into BuildConfig, restrict them in the provider console by package name and SHA-1, and keep truly secret keys on your backend, which proxies the calls. Use Play Integrity or App Check to reduce abuse from modified apps.
11

Explain the steps to publish an app on the Play Store.

Save to ▾
Show answer
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.
12

A teammate uses !! everywhere to silence compiler errors. How do you handle this in code review?

Save to ▾
Show answer
Explain calmly that !! converts a compile-time check into a possible runtime crash. Suggest alternatives per case: safe calls with ?.let, Elvis with a default or early return, requireNotNull with a clear message, or fixing the type at the source so it is non-null. Add a detekt rule to flag !! in new code. Pair with them on one file so the change feels like help, not criticism.
13

What is a use case in the domain layer and when is it worth adding?

Save to ▾
Show answer
A use case is a class with one job, like GetDiscountedCartTotalUseCase, typically exposing operator fun invoke. It holds business logic that combines repositories or is reused by several ViewModels. It keeps ViewModels thin and logic testable. For simple apps where the ViewModel only calls one repository method, use cases add boilerplate without benefit, so the domain layer is optional in the official guidance.
14

Write a Room database class with a migration that adds a column.

Save to ▾
Show answer
@Database(entities = [NoteEntity::class], version = 2, exportSchema = true) abstract class AppDatabase : RoomDatabase() { abstract fun noteDao(): NoteDao } val MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL("ALTER TABLE notes ADD COLUMN pinned INTEGER NOT NULL DEFAULT 0") } } val db = Room.databaseBuilder(context, AppDatabase::class.java, "app.db") .addMigrations(MIGRATION_1_2) .build()
15

What do flatMapLatest, flatMapConcat and flatMapMerge do?

Save to ▾
Show answer
All map each value to a new flow and flatten the results. flatMapLatest cancels the previous inner flow when a new value arrives, perfect for search. flatMapConcat waits for each inner flow to finish before starting the next, preserving order. flatMapMerge runs inner flows concurrently up to a concurrency limit, useful for parallel downloads where order does not matter. Choosing wrongly can cause stale results or wasted network calls.
16

Write code to save and read a dark mode preference with Preferences DataStore.

Save to ▾
Show answer
val Context.dataStore by preferencesDataStore(name = "settings") private val DARK_MODE = booleanPreferencesKey("dark_mode") class SettingsRepository(private val context: Context) { val darkMode: Flow<Boolean> = context.dataStore.data .catch { emit(emptyPreferences()) } .map { it[DARK_MODE] ?: false } suspend fun setDarkMode(enabled: Boolean) { context.dataStore.edit { it[DARK_MODE] = enabled } } }
17

How do you handle one-time navigation after a successful login in MVVM?

Save to ▾
Show answer
Recommended practice is to reflect the result in state, such as isLoggedIn = true in UiState, and have the UI react with LaunchedEffect(state.isLoggedIn) to navigate, then the ViewModel marks it consumed if needed. An alternative is a Channel exposed as Flow and collected with lifecycle awareness. Avoid calling navigation directly from the ViewModel, because it should not reference NavController or views.
18

How do you make Compose UI accessible?

Save to ▾
Show answer
Give icons and images a meaningful contentDescription, or null when decorative. Keep touch targets at least 48dp, which Material components handle by default. Use semantics modifiers to merge descendants for list items, mark headings with heading(), and describe custom actions. Support font scaling by using sp and avoiding fixed heights for text. Check colour contrast and test with TalkBack and the Accessibility Scanner.
19

Explain how you would use Room with Kotlin Multiplatform.

Save to ▾
Show answer
Since Room 2.7, Room supports Kotlin Multiplatform for Android, iOS and desktop. You define entities, DAOs and the database in commonMain, use the bundled SQLite driver, and create the database builder in platform-specific source sets with expect and actual. DAO functions must be suspend or return Flow in common code. This lets teams share the data layer while keeping native UIs, which some Indian product companies are adopting.
20

What is the difference between lateinit and by lazy?

Save to ▾
Show answer
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.
21

What are the four main Android app components?

Save to ▾
Show answer
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.
22

How do LazyColumn keys improve performance and correctness?

Save to ▾
Show answer
By default, items are identified by position, so inserting or deleting an item can make Compose reuse state for the wrong item and recompose more than needed. Supplying key = { it.id } gives each item a stable identity, so remembered state, animations with animateItem and scroll position follow the right item. Also supply contentType for mixed lists so compositions are reused efficiently. Keys must be unique and Bundle-saveable.
23

How should a Fragment or Activity collect a Flow safely?

Save to ▾
Show answer
Use lifecycleScope.launch with repeatOnLifecycle(Lifecycle.State.STARTED) so collection starts when the UI is visible and stops in the background, avoiding wasted work and crashes from updating views that are not ready. In a Fragment, use viewLifecycleOwner.lifecycleScope because the fragment view can be destroyed while the fragment lives. In Compose, use collectAsStateWithLifecycle(), which does the same lifecycle-aware collection.
24

How do you handle exceptions in coroutines?

Save to ▾
Show answer
Use try-catch around suspend calls for expected failures like network errors; this is the clearest approach. A CoroutineExceptionHandler on a root launch catches uncaught exceptions as a last resort for logging, but it does not work for async or child coroutines. For async, exceptions surface at await. Always rethrow CancellationException. Many teams wrap results in a Result or sealed type so the UI layer gets an explicit error state.
25

A new developer asks why we need interfaces for every repository. How do you answer?

Save to ▾
Show answer
Interfaces let us swap implementations, mainly fakes in tests and alternate data sources, and they define clear contracts between modules so feature modules depend on abstractions instead of concrete network code. But the rule is not absolute: if a class has one implementation and is easy to test directly, an interface adds noise. I would explain the reason with an example test and our team convention.
26

Tell me about a time you worked closely with a backend team to solve a problem.

Save to ▾
Show answer
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.
27

Users on slow 2G and 3G networks in small towns report the app keeps failing. How do you improve it?

Save to ▾
Show answer
Set reasonable connect and read timeouts, retry idempotent requests with exponential backoff, and cache responses so screens show something offline. Reduce payload size with gzip, pagination and fields filtering, and load images in smaller sizes with placeholders. Show clear offline and retry states instead of generic errors. Test with the emulator network throttling and real devices on poor connections, and track failure rates by network type.
28

Write code to request camera permission using the Activity Result API.

Save to ▾
Show answer
private val cameraPermission = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { granted -> if (granted) openCamera() else showPermissionDenied() } fun onScanClicked() { when { ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED -> openCamera() shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> showRationale { cameraPermission.launch(Manifest.permission.CAMERA) } else -> cameraPermission.launch(Manifest.permission.CAMERA) } }
29

How do you structure a large Android app into modules?

Save to ▾
Show answer
Common practice is feature modules (feature:cart, feature:profile), core modules (core:network, core:database, core:designsystem, core:model) and an app module that wires them together. Feature modules depend on core modules but not on each other; navigation is connected through the app module or route contracts. Benefits are faster incremental builds, clear ownership and enforced boundaries. Gradle convention plugins keep module build files consistent.
30

How do you model API results and errors cleanly for the UI?

Save to ▾
Show answer
Map transport-level outcomes into a sealed result type in the data layer, for example Success(data), HttpError(code, message) and NetworkError. Catch IOException for connectivity, HttpException for non-2xx codes, and serialization exceptions for bad payloads, and never catch CancellationException. The ViewModel converts these into user-friendly UiState messages. Keep DTOs separate from domain models so API changes do not ripple through the UI.
31

Explain the network security configuration file.

Save to ▾
Show answer
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.
32

What is targetSdkVersion and why does Play enforce updates?

Save to ▾
Show answer
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.
33

How do you test Retrofit networking code?

Save to ▾
Show answer
Use OkHttp MockWebServer to run a local server, enqueue responses with specific status codes, bodies and delays, and point Retrofit's base URL to it. Then call the API or repository and assert parsing, headers, error mapping and retry behaviour. Store sample JSON in test resources. For ViewModel tests, replace the repository with a fake instead of using MockWebServer, which keeps them fast.
34

How do you migrate from SharedPreferences to DataStore without losing user data?

Save to ▾
Show answer
Use SharedPreferencesMigration when creating the DataStore: preferencesDataStore(name = "settings", produceMigrations = { ctx -> listOf(SharedPreferencesMigration(ctx, "old_prefs")) }). On first access, DataStore copies the values and deletes the old file. Update all reads and writes to go through the new repository at once, because mixing both stores leads to inconsistent values. Test the migration with existing preference files.
35

Compare kotlinx.serialization, Moshi and Gson for JSON parsing.

Save to ▾
Show answer
kotlinx.serialization is Kotlin-first, uses a compiler plugin with no reflection, respects default values and nullability, and works in Kotlin Multiplatform. Moshi supports Kotlin through codegen and is also reliable. Gson uses reflection, ignores Kotlin nullability and default values, and can put null into non-null fields, causing crashes later; it is in maintenance mode. For new Android projects, kotlinx.serialization is the common choice.
36

What is a BroadcastReceiver and what limits apply since Android 8?

Save to ▾
Show answer
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.

Frequently asked questions

Which companies hire Android App Development professionals in Ahmedabad?

Companies with large offices in Ahmedabad include many IT services and product firms. Use their company pages below to practise employer-specific sets.

Are Android App Development interviews in Ahmedabad different from other cities?

The questions depend more on the company than the city. Ahmedabad's mix of employers decides the style: Companies here value hands-on skills and the ability to work across tools, especially in smaller teams

How do I find Android App Development jobs in Ahmedabad?

Shortlist companies with Ahmedabad offices, keep your CV focused on Android App Development projects, apply on company career pages and job portals with the Ahmedabad filter, and practise the questions on this page before each interview.