Senior Android Developer Interview Questions: Kotlin, Compose, Architecture

Milad Bonakdar
Author
Prepare for senior Android interviews with practical questions on Kotlin coroutines, Jetpack Compose state, app architecture, performance, testing, offline-first data, and security.
Introduction
For a senior Android developer interview, prepare to explain architecture trade-offs, lifecycle-safe concurrency, Compose state ownership, offline-first data flow, performance diagnosis, testing strategy, and security. A strong answer should show not only what API you would use, but why it fits the product constraint and how you would debug it in production.
Use this guide as a practical checklist. Focus first on Kotlin coroutines and Flow, ViewModel and state management, Room-backed repositories, Compose versus legacy UI decisions, startup and memory performance, and the examples you can explain from your own apps.
How to use these questions
- Practice each answer as a short decision: context, trade-off, implementation, failure mode.
- Connect technical choices to user impact, such as faster startup, reliable offline reads, safer token storage, or fewer lifecycle bugs.
- Prepare one real project story for architecture, performance, testing, and security.
Advanced Kotlin & Language Features (5 Questions)
1. Explain Kotlin Coroutines and their advantages over threads.
Answer: Kotlin coroutines let Android apps run asynchronous work without blocking the main thread. In a senior interview, do not describe them only as "lightweight threads". Explain lifecycle ownership, cancellation, dispatcher choice, error handling, and how the result reaches UI state.
- Why they matter: Coroutines make network, database, and CPU work easier to compose while keeping UI code readable.
- Structured concurrency: Work launched in a parent scope is cancelled with that scope, which prevents many leaks and orphaned tasks.
- Android lifecycle fit:
viewModelScopeis usually right for screen state because its work is cancelled when theViewModelis cleared. Use lifecycle-aware collection from the UI so Flow collection stops when the screen is not active. - Dispatcher choice: Use
Dispatchers.IOfor blocking I/O,Dispatchers.Defaultfor CPU-heavy work, and return to Main for UI state. - Senior trade-off: Coroutines do not remove the need for timeouts, retries, idempotency, clear ownership, and observable error states.
Rarity: Very Common Difficulty: Hard
2. What are Sealed Classes and when should you use them?
Answer: Sealed classes represent restricted class hierarchies where all subclasses are known at compile time.
- Benefits:
- Exhaustive
whenexpressions - Type-safe state management
- Better than enums for complex data
- Exhaustive
- Use Cases: Representing states, results, navigation events
Rarity: Common Difficulty: Medium
3. Explain Kotlin Flow and how it differs from LiveData.
Answer: Flow is Kotlin's asynchronous stream API. It is a strong fit for Android data and UI state because repositories can expose changing data, ViewModels can transform it, and the UI can collect it with lifecycle awareness.
- Flow: Cold by default. The upstream work starts when a collector subscribes. Good for streams from repositories and use cases.
- StateFlow: Hot state holder with a current value. Good for screen state exposed by a ViewModel.
- SharedFlow: Hot stream for events that do not naturally have one current value. Use it carefully for one-off UI events.
- LiveData: Android-specific and lifecycle-aware by default, but less flexible for operators, structured concurrency, and non-Android layers.
- Senior trade-off: Avoid collecting flows directly forever in an Activity or Fragment. Use lifecycle-aware collection, keep business streams outside UI classes, and choose
stateInorshareInonly when the sharing behavior is intentional.
Rarity: Very Common Difficulty: Hard
4. What are Inline Functions and when should you use them?
Answer: Inline functions copy the function body to the call site, avoiding function call overhead.
- Benefits:
- Eliminates lambda allocation overhead
- Allows non-local returns from lambdas
- Better performance for higher-order functions
- Use Cases: Higher-order functions with lambda parameters
- Trade-off: Increases code size
Rarity: Medium Difficulty: Hard
5. Explain Delegation in Kotlin.
Answer: Delegation allows an object to delegate some of its responsibilities to another object.
- Class Delegation:
bykeyword - Property Delegation: Lazy, observable, delegates
- Benefits: Code reuse, composition over inheritance
Rarity: Medium Difficulty: Medium
Architecture Patterns (6 Questions)
6. Explain MVVM architecture and its benefits.
Answer: MVVM (Model-View-ViewModel) separates UI logic from business logic.
- Model: Data layer (repositories, data sources)
- View: UI layer (Activities, Fragments, Composables)
- ViewModel: Presentation logic, survives configuration changes
- Benefits: Testable, separation of concerns, lifecycle-aware
Rarity: Very Common Difficulty: Medium
7. What is Clean Architecture and how do you implement it in Android?
Answer: Clean Architecture separates code into layers with clear dependencies.
- Presentation: UI, ViewModels
- Domain: Use Cases, Business Logic, Entities
- Data: Repositories, Data Sources (API, Database)
- Dependency Rule: Inner layers don't know about outer layers
Rarity: Common Difficulty: Hard
8. Explain Dependency Injection and Dagger/Hilt.
Answer: Dependency Injection provides dependencies to classes instead of creating them internally.
- Benefits: Testability, loose coupling, reusability
- Dagger: Compile-time DI framework
- Hilt: Simplified Dagger for Android
Rarity: Very Common Difficulty: Hard
9. What is the Repository pattern and why use it?
Answer: The Repository pattern gives the rest of the app a stable API for data while hiding whether that data comes from Room, a network API, a cache, or another source. For senior Android roles, the important point is ownership: in an offline-first design, the local database is often the source of truth that the UI observes, while network refreshes update that local source.
- Benefits: Clear data ownership, easier testing, consistent offline behavior, and less duplication across ViewModels.
- Good boundary: ViewModels request data and actions; repositories coordinate local and remote sources; DAOs and API clients stay implementation details.
- Common mistake: Emitting remote data directly to the UI while also writing to Room can create inconsistent states. Prefer one observable source of truth when possible.
- Interview signal: Explain conflict handling, stale data, retry behavior, pagination, and how the repository reports loading and errors without blocking reads.
Rarity: Very Common Difficulty: Medium
10. Explain the Single Activity architecture.
Answer: Single Activity architecture uses one Activity with multiple Fragments, managed by Navigation Component.
- Benefits:
- Simplified navigation
- Shared ViewModels between fragments
- Better animations
- Easier deep linking
- Navigation Component: Handles fragment transactions, back stack, arguments
Rarity: Common Difficulty: Medium
11. What is MVI (Model-View-Intent) architecture?
Answer: MVI is a unidirectional data flow architecture inspired by Redux.
- Components:
- Model: Represents UI state
- View: Renders state, emits intents
- Intent: User actions/events
- Benefits: Predictable state, easier debugging, time-travel debugging
Rarity: Medium Difficulty: Hard
Performance & Optimization (5 Questions)
12. How do you optimize RecyclerView performance?
Answer: Multiple strategies improve RecyclerView scrolling performance:
- ViewHolder Pattern: Reuse views (built-in)
- DiffUtil: Efficient list updates
- Stable IDs: Override
getItemId()andsetHasStableIds(true) - Prefetching: Increase prefetch distance
- Image Loading: Use libraries like Glide/Coil with proper sizing
- Avoid Heavy Operations: Don't perform expensive calculations in
onBindViewHolder - Nested RecyclerViews: Set
setRecycledViewPool()andsetHasFixedSize(true)
Rarity: Very Common Difficulty: Medium
13. How do you detect and fix memory leaks in Android?
Answer: Memory leaks occur when objects are held in memory longer than needed.
- Common Causes:
- Context leaks (Activity/Fragment references)
- Static references
- Anonymous inner classes
- Listeners not unregistered
- Coroutines not cancelled
- Detection Tools:
- LeakCanary library
- Android Studio Memory Profiler
- Heap dumps
Rarity: Very Common Difficulty: Medium
14. How do you optimize app startup time?
Answer: Faster startup improves user experience:
- Lazy Initialization: Initialize objects only when needed
- Avoid Heavy Work in Application.onCreate():
- Move to background thread
- Defer non-critical initialization
- Content Providers: Minimize or lazy-load
- Reduce Dependencies: Fewer libraries = faster startup
- App Startup Library: Structured initialization
- Baseline Profiles: Ahead-of-time compilation hints
Rarity: Common Difficulty: Medium
15. How do you handle bitmap loading and caching efficiently?
Answer: Efficient image handling is crucial for performance:
- Libraries: Glide, Coil (handle caching automatically)
- Manual Optimization:
- Downsampling (load smaller images)
- Memory cache (LruCache)
- Disk cache
- Bitmap pooling
Rarity: Common Difficulty: Hard
16. What is ANR and how do you prevent it?
Answer: ANR (Application Not Responding) occurs when the main thread is blocked for too long.
- Causes:
- Heavy computation on main thread
- Network calls on main thread
- Database operations on main thread
- Deadlocks
- Prevention:
- Move heavy work to background threads
- Use coroutines with proper dispatchers
- Avoid synchronized blocks on main thread
- Use WorkManager for background tasks
Rarity: Common Difficulty: Easy
Testing (3 Questions)
17. How do you write unit tests for ViewModels?
Answer: ViewModels should be tested in isolation with mocked dependencies.
Rarity: Very Common Difficulty: Medium
18. What is the difference between Unit, Integration, and UI tests?
Answer:
- Unit Tests:
- Test individual components in isolation
- Fast, run on JVM
- Mock dependencies
- Example: ViewModel, Repository, Use Case tests
- Integration Tests:
- Test how components work together
- May require Android framework
- Example: Repository with real database
- UI Tests (Instrumented):
- Test user interactions
- Run on device/emulator
- Slower but verify actual behavior
- Example: Espresso tests
Rarity: Common Difficulty: Easy
19. How do you test Coroutines and Flow?
Answer: Use testing libraries designed for coroutines.
Rarity: Common Difficulty: Medium
Security & Best Practices (2 Questions)
20. How do you secure sensitive data in Android?
Answer: Android security is a layered design problem, not a single library choice. In a senior interview, separate data-at-rest protection, network protection, authentication/session handling, logging, and abuse resistance.
- Store less sensitive data: Do not persist tokens or personal data unless the app truly needs it.
- Use Android Keystore-backed encryption: Store keys in Android Keystore and use encrypted storage for small secrets.
- Protect network traffic: Use HTTPS, a clear Network Security Config, and certificate pinning only when the team can handle rotation and incident response.
- Avoid leaking secrets: Keep tokens out of logs, crash reports, analytics events, screenshots, backups, and deep links.
- Harden release builds: Use R8/obfuscation, dependency updates, Play Integrity or similar checks where appropriate, and server-side validation for anything security-sensitive.
Rarity: Common Difficulty: Hard
21. What are Android best practices for production apps?
Answer: Production Android best practices are about making the app reliable under real device, network, and team constraints. A senior answer should connect code structure to operability.
- Architecture: Keep UI, domain, and data responsibilities clear; avoid architecture that adds ceremony without solving a real coordination problem.
- State management: Expose predictable UI state from ViewModels and collect it with lifecycle awareness.
- Offline behavior: Decide what must work without network access and make the local source of truth explicit.
- Performance: Track startup, memory, jank, battery, and network usage before and after major changes.
- Testing: Cover ViewModels, use cases, repositories, database migrations, and critical UI flows with the right level of test.
- Security and privacy: Store less data, encrypt sensitive local data, protect network calls, and avoid leaking personal information through logs or analytics.
- Accessibility and localization: Design for TalkBack, scalable text, content descriptions, contrast, and markets you actually support.
- Release discipline: Use feature flags where helpful, staged rollout, crash monitoring, rollback plans, and clear ownership for incidents.
Rarity: Common Difficulty: Medium


