Skip to content

TCS Android App Development Interview Questions & Answers

Curated interview practice questions with answers. These are practice scenarios, not a verified list of past interview questions.

About TCS hiring for Android App Development roles

Tata Consultancy Services is a Tata Group company and one of the largest IT services and consulting firms in the world. It delivers application development, testing, cloud, data and analytics services to clients in banking, retail, manufacturing and other industries. In India it hires freshers and experienced staff for software testing, data engineering, BI reporting and analytics roles across its delivery centres.

For Android App Development roles, this TCS practice set focuses most on Kotlin Fundamentals (5), Jetpack Compose (5), Testing, Performance and Play Store (4), Coroutines and Flow (4). It has 11 easy, 15 medium, 4 hard questions, so you can start easy and work up to the harder ones.

Company type
IT services
Headquarters
Mumbai, India
Main India offices
Mumbai, Chennai, Pune, Bengaluru, Hyderabad

TCS Android App Development interview process

  1. TCS NQT online assessment (aptitude + coding)
  2. Technical interview
  3. Managerial round
  4. HR round

Typical pattern based on public candidate experiences. Rounds vary by role, team and year.

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

Explain object, companion object and object expressions.

Save to ▾
Show answer
An object declaration creates a thread-safe singleton initialised lazily on first access. A companion object is an object tied to a class, used for factory methods and constants, similar to static members in Java; add @JvmStatic for Java callers. An object expression creates an anonymous object on the spot, often to implement an interface such as a callback. Avoid holding Context or Activity references in singletons to prevent memory leaks.
02

Write a unit test for a ViewModel using a fake repository and runTest.

Save to ▾
Show answer
class ProductViewModelTest { @get:Rule val mainRule = MainDispatcherRule() @Test fun loadsProductsIntoState() = runTest { val fake = FakeProductRepository(listOf(Product("1", "Pen", 10.0))) val vm = ProductViewModel(fake) advanceUntilIdle() val state = vm.state.value assertFalse(state.loading) assertEquals(1, state.items.size) assertNull(state.error) } }
03

What does the suspend keyword mean?

Save to ▾
Show answer
suspend marks a function that can pause and resume later without blocking the thread. It can only be called from another suspend function or a coroutine. The compiler transforms it using continuation-passing style into a state machine. suspend alone does not move work to a background thread; the function must use withContext(Dispatchers.IO) or a main-safe library like Retrofit or Room to avoid blocking the main thread.
04

What is Kotlin Flow and how is it different from a suspend function?

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

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.
06

Tell me about an app or feature you are proud of building.

Save to ▾
Show answer
Choose something with clear impact. For example: I built the offline cart for our grocery app. Users in low network areas could add items without connection, and the cart synced later with conflict handling. I used Room, WorkManager and a sync status field, and wrote migration and sync tests. After release, cart abandonment from network errors dropped noticeably, and the pattern was reused for the wishlist feature.
07

Why should a ViewModel never hold a reference to an Activity, Fragment or View?

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

Write a HiltViewModel that exposes a single UiState using StateFlow.

Save to ▾
Show answer
data class ProductUiState( val loading: Boolean = true, val items: List<Product> = emptyList(), val error: String? = null ) @HiltViewModel class ProductViewModel @Inject constructor( private val repo: ProductRepository ) : ViewModel() { private val _state = MutableStateFlow(ProductUiState()) val state: StateFlow<ProductUiState> = _state.asStateFlow() init { refresh() } fun refresh() = viewModelScope.launch { _state.update { it.copy(loading = true, error = null) } runCatching { repo.fetchProducts() } .onSuccess { list -> _state.update { it.copy(loading = false, items = list) } } .onFailure { _state.update { it.copy(loading = false, error = "Try again") } } } }
09

How do default and named arguments reduce the need for overloads?

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

A screen shows a snackbar again every time the device rotates. How do you fix it?

Save to ▾
Show answer
The event is probably stored as state in a StateFlow or LiveData, so it is re-delivered when the new Activity collects again. Options: model it as part of UI state and have the UI call a function like onMessageShown() to clear it after display, which is the approach the official guidance recommends; or send it through a Channel exposed with receiveAsFlow so each event is consumed once. Collect with lifecycle awareness to avoid losing events.
11

How do you collect a ViewModel StateFlow in a composable?

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

How do you store sensitive data such as tokens securely on Android?

Save to ▾
Show answer
Never store secrets in plain SharedPreferences or hardcode them in code. Use the Android Keystore to generate a key that never leaves secure hardware, and encrypt the data before storing it in DataStore or a file. The security-crypto EncryptedSharedPreferences library is deprecated, so many teams use Tink with Keystore. Keep tokens short-lived with refresh tokens, and clear them on logout. Exclude them from backups.
13

What does the inline keyword do and when should you use reified?

Save to ▾
Show answer
inline tells the compiler to copy the function body and lambda bodies into the call site, avoiding the object allocation for lambdas and enabling non-local returns. It suits small higher-order functions called often. reified can only be used in inline functions and keeps the generic type available at runtime, so you can write inline fun <reified T> Gson.fromJson(json: String) and use T::class. Avoid inlining large functions since it increases bytecode size.
14

What is the difference between launch and async?

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

What is the difference between a started service, bound service and foreground service?

Save to ▾
Show answer
A started service runs after startService until it stops itself. A bound service offers a client-server interface to components that bind to it and stops when all unbind. A foreground service shows a persistent notification and has higher priority, used for music, navigation or ongoing calls. Since Android 14 a foreground service must declare a type such as mediaPlayback or location. For deferrable background work, use WorkManager instead.
16

Tell me about a time you disagreed with a designer about a UI decision.

Save to ▾
Show answer
Situation: a designer wanted a custom tiny close icon on a full-screen dialog. Task: keep the app accessible without blocking the design. Action: I showed that the touch target was below the 48dp guideline and that TalkBack had no label, and prototyped the same look with a larger invisible touch area. Result: we kept the visual style, passed accessibility checks, and agreed to review touch targets in future design handoffs.
17

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 } } }
18

What is an Android App Bundle and why does Play require it?

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

Images in a feed load slowly and the app runs out of memory. What do you change?

Save to ▾
Show answer
Use an image library like Coil, which handles memory and disk caching, request downsampling to the view size, and cancellation when items scroll away. Ask the backend or CDN for resized, compressed images such as WebP instead of full-size originals. Use placeholders and crossfade, avoid holding Bitmaps in ViewModels, and set memory cache limits. Profile with Memory Profiler to confirm the large allocations are gone.
20

Explain LaunchedEffect, DisposableEffect and SideEffect.

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

Write a function that retries a suspend call with exponential backoff.

Save to ▾
Show answer
suspend fun <T> retryWithBackoff( times: Int = 3, initialDelay: Long = 500, factor: Double = 2.0, block: suspend () -> T ): T { var delayMs = initialDelay repeat(times - 1) { try { return block() } catch (e: IOException) { /* retry */ } delay(delayMs) delayMs = (delayMs * factor).toLong() } return block() }
22

What are sequences in Kotlin and when are they better than collections?

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

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.
24

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.
25

What conflict strategies does Room offer for inserts?

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

What is CompositionLocal and when should you use it?

Save to ▾
Show answer
CompositionLocal passes data implicitly down the tree without threading it through every parameter, like LocalContext, LocalDensity or MaterialTheme values. Create one with compositionLocalOf when values change often, or staticCompositionLocalOf when they rarely change. Use it for cross-cutting values like theme or analytics loggers, not for regular screen data, because implicit dependencies make composables harder to understand and test.
27

What is MVVM and why is it recommended for Android?

Save to ▾
Show answer
MVVM splits an app into Model (data and business logic), View (Activity, Fragment or composable that renders state) and ViewModel (holds UI state and handles user events). The ViewModel survives configuration changes and has no reference to views, so it is easy to unit test. The View observes state from the ViewModel through StateFlow or LiveData. This separation reduces bugs from lifecycle issues and keeps UI code thin.
28

What does derivedStateOf do and when should you use it?

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

How do runtime permissions work in modern Android?

Save to ▾
Show answer
Dangerous permissions like camera, location and notifications (POST_NOTIFICATIONS since Android 13) must be declared in the manifest and requested at runtime. Use the Activity Result API with RequestPermission or RequestMultiplePermissions contracts. Show a rationale when shouldShowRequestPermissionRationale returns true, handle denial gracefully, and direct users to settings if they deny permanently. Request permissions in context, at the moment the feature needs them.
30

What are Baseline Profiles?

Save to ▾
Show answer
A Baseline Profile is a list of classes and methods used in critical journeys like startup and scrolling, shipped with the app. The Android Runtime uses it to compile that code ahead of time on install, avoiding slow interpretation and JIT on first runs. You generate it with the Baseline Profile Gradle plugin and Macrobenchmark tests. Compose and many Jetpack libraries ship their own profiles, but an app-specific one gives larger gains.

Tips to crack the TCS Android App Development interview

  • Practise TCS NQT style numerical, verbal and reasoning sections along with two basic coding problems under strict time limits.
  • Be ready to explain your final-year project, SQL basics and core concepts like OOP, DBMS and software testing life cycle.
  • Read about TCS service lines such as BFSI and its iON and Ignio platforms to answer why you want to join.
  • Keep a one-minute story ready for every project on your CV: problem, your part, tools, result.
  • Practise the hard questions on this page aloud; TCS interviewers usually ask follow-ups on your first answer.

Frequently asked questions

How many rounds are there in the TCS Android App Development interview?

Candidates usually go through 4 stages: TCS NQT online assessment (aptitude + coding); Technical interview; Managerial round; HR round. The exact rounds change with the role, team, location and your experience, so confirm the process with the recruiter.

Which topics should I prepare for the TCS Android App Development interview?

This practice set leans on Kotlin Fundamentals (5), Jetpack Compose (5), Testing, Performance and Play Store (4), Coroutines and Flow (4). Revise those first, then practise explaining one or two of your own projects end to end, because most TCS interviewers ask you to walk through real work.

Are these the exact questions asked at TCS?

No. These are curated practice questions that match the skills and difficulty usually tested in it services interviews like TCS's. They are not a leaked or verified list of past questions.

Where does TCS hire Android App Development professionals in India?

TCS has large teams in Mumbai, Chennai, Pune, Bengaluru, Hyderabad. Openings and locations change often, so check the TCS careers page and filter by city and experience.

Android App Development questions for similar companies