Android App Development Interview Questions in Bhubaneswar
36 practice questions with answers for Android App Development interviews in Bhubaneswar.
Android App Development jobs in Bhubaneswar
Bhubaneswar is eastern India's emerging IT hub, with campuses of large IT-services companies in Infocity and Info Valley. Freshers make up a big share of hiring, so fundamentals and aptitude rounds matter most.
Below are 36 questions that match the mix of service, product and domain employers hiring junior android developers in Bhubaneswar.
Solved for BhubaneswarStart 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 do LazyColumn keys improve performance and correctness?
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.
Modifiers are applied in a chain from left to right, each wrapping the next. Modifier.padding(16.dp).background(Color.Red) adds padding outside the red area, while background first then padding colours the padding too. Similarly, clickable before padding makes the whole padded area clickable. Thinking of each modifier as wrapping the content after it helps predict layout, size and touch target behaviour.
03
Explain LaunchedEffect, DisposableEffect and SideEffect.
LaunchedEffect(key) launches a coroutine when it enters composition and restarts when the key changes, used for one-time loads or showing a snackbar. DisposableEffect(key) runs setup and requires an onDispose block for cleanup, used for registering listeners or lifecycle observers. SideEffect runs after every successful recomposition to publish Compose state to non-Compose code, such as analytics. Choose keys carefully so effects do not restart unexpectedly.
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
Write a periodic sync job with WorkManager that runs only on unmetered network.
Dispatchers.Main runs on the Android UI thread and is used for updating views or state. Dispatchers.IO uses a large shared pool, by default up to 64 threads, for blocking work like disk and network. Dispatchers.Default uses a pool sized to CPU cores for CPU-heavy work like sorting, parsing large JSON or image processing. Use withContext to switch, and keep suspend functions main-safe so callers do not need to know.
07
You need to sync 500 images to a server without overloading the network. How would you design it with coroutines?
Limit concurrency. Use a Semaphore with withPermit around each upload, or flatMapMerge(concurrency = 4) over a flow of files, or Dispatchers.IO.limitedParallelism(4). Use supervisorScope so one failed upload does not cancel the rest, collect failures for retry with backoff, and report progress through a StateFlow. If the sync must survive app exit, run it inside a CoroutineWorker with WorkManager constraints such as network connected.
08
How does coroutine cancellation work, and why must code be cooperative?
Cancelling a Job sets it to cancelling state, and the next suspension point such as delay, withContext or a suspending library call throws CancellationException. A tight CPU loop with no suspension keeps running, so check isActive or call ensureActive() or yield() inside it. Do not swallow CancellationException in a generic catch block; rethrow it. Use finally or withContext(NonCancellable) for cleanup that must finish.
WorkManager schedules deferrable, guaranteed background work that must run even if the app exits or the device restarts, such as syncing data, uploading logs or backing up photos. It supports constraints like network or charging, retries with backoff, chaining and unique work. It is not for exact-time tasks or work that must finish immediately while the user waits; use coroutines for that and AlarmManager for exact alarms.
Both separate UI from logic. MVI (Model-View-Intent) is stricter: the UI sends intents or actions, a reducer produces a single new immutable state, and side effects are handled separately. It gives one state object per screen and an easy-to-replay history. MVVM is more flexible, sometimes exposing several streams. In practice many Compose apps use MVVM with a single UiState data class, which is close to MVI.
11
The app shows an ANR when the user taps Save. The save function is suspend. What could be wrong?
A suspend function does not automatically run off the main thread. If it calls blocking code, like a synchronous file write, a SharedPreferences commit, a blocking SDK or heavy JSON parsing, it still blocks the main thread. Check with a profiler or StrictMode. Fix by wrapping the blocking part in withContext(Dispatchers.IO) or Default, or by using main-safe APIs such as Room suspend DAOs or DataStore.
Compose skips recomposing a composable when all its parameters are stable and equal to before. Primitives, String, functions and data classes with val stable properties are stable. Classes with var properties, standard List or types from modules without the Compose compiler may be unstable, preventing skipping. Since strong skipping mode became default in Kotlin 2.0.20, unstable parameters are compared by instance, reducing the problem, but immutable models still help.
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.
14
A Room query on a large table is slow and causes jank. How do you fix it?
Make sure the query runs off the main thread using suspend or Flow. Use EXPLAIN QUERY PLAN to check for full table scans, and add an @Index on columns used in WHERE, JOIN or ORDER BY. Select only needed columns into a smaller data class instead of SELECT *, page results with Paging 3, and avoid loading large blobs into lists. Wrap bulk inserts in a single transaction.
15
Two screens show different values for the same cart count. How do you fix the architecture?
Each screen probably fetches and caches its own copy. Create a single CartRepository, scoped as a singleton, that owns cart data in Room or an in-memory StateFlow, and have both ViewModels observe its Flow instead of keeping private copies. Mutations go through the repository so every observer updates automatically. This enforces the single source of truth and removes the need for manual refresh calls between screens.
16
Users who reinstall the app lose all their settings. How can you restore them?
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.
Create an in-memory database with Room.inMemoryDatabaseBuilder in an instrumented test or with Robolectric, get the DAO, insert test data and assert query results. For Flow queries, collect the first value with first() or use Turbine. Close the database in @After. Test edge cases like conflict strategies and ordering. In-memory databases are fast and isolated, so each test starts clean.
18
Explain the Fragment lifecycle and why viewLifecycleOwner matters.
A Fragment has its own lifecycle (onCreate to onDestroy) and a separate view lifecycle (onCreateView to onDestroyView). When a fragment goes to the back stack its view is destroyed but the fragment instance may stay. If you observe LiveData or collect flows with the fragment itself as owner, observers pile up and can touch a dead view. Use viewLifecycleOwner and clear view binding references in onDestroyView.
19
You are starting a new app for a fintech startup. Which architecture and libraries would you choose and why?
I would use Kotlin, Jetpack Compose with Material 3, MVVM with unidirectional data flow, Hilt for DI, Coroutines and Flow, Retrofit with OkHttp and kotlinx.serialization, Room for offline data, DataStore for preferences, WorkManager for background sync, and Navigation Compose. For fintech, add certificate pinning considerations, encrypted storage via Keystore, Play Integrity checks, and strong test coverage. Start modular from day one with core and feature modules.
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.
22
What happens on a configuration change such as screen rotation?
By default the system destroys and recreates the Activity so it can load resources for the new configuration, like landscape layouts or a new language. Fields in the Activity are lost, but a ViewModel survives because it is kept by the ViewModelStore. Views with IDs restore some state automatically, and rememberSaveable in Compose restores small state. Handling changes manually via configChanges is possible but should be a deliberate choice.
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.
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.
25
Explain the difference between let, run, with, apply and also.
All are scope functions that run a block on an object. let and also receive the object as it; run, with and apply receive it as this. let, run and with return the lambda result, while apply and also return the object itself. Typical use: let for null checks (user?.let { }), apply for configuring an object, also for side effects like logging, and run or with for computing a result from an object.
26
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.
27
What are sequences in Kotlin and when are they better than collections?
Sequences evaluate lazily, element by element, while collection operations like map and filter create a new intermediate list at every step. For long chains on large data, or when you only need the first few results with take or first, asSequence() avoids extra allocations. For small lists, plain collections are often faster because sequences add per-element overhead. Measure before switching in performance-critical code.
28
What is the predictive back gesture and how do you support it?
Predictive back, introduced in Android 13 and on by default for apps targeting Android 15, shows a preview of the destination while the user swipes back. Support it by setting android:enableOnBackInvokedCallback="true" and handling back with OnBackPressedDispatcher or BackHandler in Compose instead of overriding onBackPressed, which is deprecated. Navigation libraries and Material components provide animations when you use the supported APIs.
Structured concurrency means every coroutine runs inside a scope, and the scope does not complete until all its children complete. If the scope is cancelled, all children are cancelled; if a child fails, the failure propagates and cancels siblings and the parent by default. This prevents leaked background work. On Android, viewModelScope and lifecycleScope tie coroutines to component lifecycles so work stops when the screen goes away.
30
What is the difference between remember and rememberSaveable?
remember keeps a value across recompositions but loses it when the composable leaves composition, on configuration change or process death. rememberSaveable stores the value in the saved instance state Bundle, so it survives rotation and process death; it works with types that can go in a Bundle or with a custom Saver. Use rememberSaveable for things like text input or selected tab, and a ViewModel for screen-level data.
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.
32
What does derivedStateOf do and when should you use it?
derivedStateOf creates state computed from other state, and only triggers recomposition when the computed result changes. A classic example is showing a scroll-to-top button: val showButton by remember { derivedStateOf { listState.firstVisibleItemIndex > 0 } }. Without it, every scroll pixel would recompose. Do not use it when the result changes as often as the input, because it only adds overhead.
33
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.
34
The backend team changed a field from a number to a string and the app crashed for all users. How do you prevent this?
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.
35
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.
36
How do you store relationships in Room, such as orders with items?
Create separate entities and link them with a foreign key column, like OrderItem.orderId. Then define a data class with @Embedded order and @Relation(parentColumn = "id", entityColumn = "orderId") items, and query it in a DAO method annotated with @Transaction so both reads are consistent. For many-to-many relations, add a cross-reference entity with junction. Add indices on foreign key columns for query speed.
Few big employers listed in Bhubaneswar?
Many Bhubaneswar candidates also apply to teams in Kolkata and to remote or hybrid roles. Practise the Kolkata set as well.
Which companies hire Android App Development professionals in Bhubaneswar?
Companies with large offices in Bhubaneswar include many IT services and product firms. Use their company pages below to practise employer-specific sets.
Are Android App Development interviews in Bhubaneswar different from other cities?
The questions depend more on the company than the city. Bhubaneswar's mix of employers decides the style: Freshers make up a big share of hiring, so fundamentals and aptitude rounds matter most
How do I find Android App Development jobs in Bhubaneswar?
Shortlist companies with Bhubaneswar offices, keep your CV focused on Android App Development projects, apply on company career pages and job portals with the Bhubaneswar filter, and practise the questions on this page before each interview.