Ace Your Android Developer Interview
Master the most asked questions, showcase your expertise, and land your dream Android role.
- Real‑world scenario based answers using the STAR method
- Clear outlines for quick review
- Evaluation criteria to self‑grade your response
- Common red flags to avoid
- Practical tips from senior Android engineers
Core Android
In a previous project, our app crashed whenever the device was rotated because the activity was recreated and state was lost.
I needed to ensure the UI retained its state across configuration changes without memory leaks.
Implemented onSaveInstanceState/onRestoreInstanceState for lightweight data and used ViewModel with LiveData to survive configuration changes. For heavy resources, I leveraged retained fragments and set android:configChanges in the manifest where appropriate.
The app handled rotations smoothly, no crashes, and user data persisted, improving user satisfaction scores by 15%.
- How would you handle a long‑running network request during rotation?
- What are the drawbacks of using android:configChanges?
- Clarity of lifecycle sequence
- Correct use of state‑preservation techniques
- Awareness of modern Jetpack components
- Understanding of trade‑offs
- Confusing onPause with onStop
- Suggesting to store large objects in Bundle
- Describe each lifecycle callback (onCreate, onStart, onResume, onPause, onStop, onDestroy)
- Explain why onDestroy may not be called on rotation
- Show how to preserve UI state with onSaveInstanceState
- Introduce ViewModel as a modern solution
- Mention configChanges as a last‑resort option
Our team needed a reusable component that displayed a list with header actions across multiple screens.
Decide whether to implement it as a Fragment or a custom View.
Evaluated requirements: lifecycle awareness, need for child fragments, and navigation handling. Chose a Fragment because it required its own lifecycle, could host a RecyclerView with its own ViewModel, and needed to participate in back‑stack navigation. Implemented the UI as a Fragment with a separate layout file, exposing an interface for the host activity.
The component was easily reused in three different activities, reduced code duplication by 30%, and navigation behaved consistently.
- Can a custom View host a ViewModel?
- How do you communicate between a Fragment and its host activity?
- Accurate distinction between Fragment and View
- Appropriate justification for choice
- Mention of communication patterns
- Saying Fragments are always better than Views
- Define Fragment (UI + lifecycle, can host child fragments)
- Define custom View (lightweight UI widget)
- Compare use‑cases: navigation, lifecycle, reuse, complexity
- State the decision criteria
Our codebase grew to 200+ classes, making manual object creation cumbersome and hard to test.
Introduce a DI framework to manage object graphs and improve testability.
Adopted Dagger 2 (later Hilt) for its compile‑time validation. Defined @Module classes to provide dependencies, used @Inject constructors for classes, and scoped components with @Singleton and @ActivityScoped. Replaced ServiceLocator pattern with constructor injection, enabling unit tests with mock implementations.
Reduced boilerplate by 40%, eliminated runtime injection errors, and increased unit test coverage from 55% to 80%.
- What are the differences between Hilt and plain Dagger?
- How would you inject a ViewModel with Hilt?
- Correct library name and annotations
- Understanding of scopes
- Link to testability
- Confusing @Provides with @Inject
- Introduce DI concept and why needed
- Name Dagger/Hilt and key annotations (@Inject, @Module, @Provides, @Singleton)
- Explain component scopes
- Show example of constructor injection
- Highlight testability benefits
Our app’s cold start time exceeded 5 seconds, leading to poor user ratings.
Identify bottlenecks and reduce launch latency.
Enabled Android App Bundle to deliver only required resources, deferred initialization of heavy libraries using the SplashScreen API, moved non‑essential work to background threads with WorkManager, applied lazy loading for Dagger modules, and profiled with Android Studio’s Startup Profiler to pinpoint slow init blocks. Also optimized the Application class and removed unnecessary reflection calls.
Cold start dropped to 2.3 seconds, warm start under 800 ms, and Play Store rating improved by 0.3 stars.
- What is the role of the SplashScreen API in startup optimization?
- How do dynamic feature modules affect startup?
- Use of profiling tools
- Specific optimization techniques
- Quantifiable results
- Vague statements like "make code faster" without details
- Measure startup with profiler
- Use App Bundle & dynamic feature modules
- Defer heavy init (libraries, DB)
- Lazy‑load DI modules
- Optimize Application class
- Avoid reflection
Architecture & Design Patterns
When joining a legacy codebase that used MVP, I needed a more lifecycle‑aware pattern.
Advocate for MVVM and demonstrate its benefits.
Described MVVM components: View (Activity/Fragment), ViewModel (holds UI data, survives config changes), LiveData (observable data holder). Compared to MVP where Presenter manually updates the View and must handle lifecycle. Showed how ViewModel reduces boilerplate and improves testability.
Team migrated two screens to MVVM, cutting presenter code by 40% and eliminating memory leaks related to view references.
- How would you handle one‑time events in MVVM?
- Can ViewModel hold a reference to Context?
- Clear component definitions
- Correct lifecycle handling
- Understanding of differences
- Saying ViewModel replaces the View entirely
- Define View, ViewModel, LiveData
- Explain data flow (View observes LiveData)
- Contrast with Presenter’s role in MVP
- Highlight lifecycle awareness and testability
We needed a type‑safe way to represent loading, success, and error states for a network call in the UI layer.
Design a Kotlin solution that the UI could observe safely.
Created a sealed class UiState with subclasses Loading, Success<T>, and Error(val message). The ViewModel exposed LiveData<UiState>. The Fragment used when‑expression to handle each subclass, ensuring compile‑time exhaustiveness. Added data class for Success payload and used sealed class to prevent invalid states.
UI handling became concise, compile‑time safe, and bugs related to unhandled states dropped to zero in code reviews.
- How does a sealed class differ from an enum class?
- Can sealed classes have state?
- Correct definition
- Practical UI example
- Understanding of exhaustiveness
- Confusing sealed with abstract class
- Define sealed class and its exhaustiveness guarantee
- Show example with Loading/Success/Error subclasses
- Explain usage in ViewModel + LiveData
- Mention when‑expression in UI
Our app mixed network and database logic directly in ViewModels, making testing difficult.
Introduce a clean separation of data sources.
Implemented a Repository interface that abstracts data operations. Created concrete classes: RemoteRepository (Retrofit) and LocalRepository (Room). The Repository decides whether to fetch from cache or network, exposing a Flow<Result<T>>. ViewModel depends only on the Repository, enabling unit tests with fake implementations.
Test coverage increased, code became modular, and swapping data sources required only changes in Repository implementations.
- How would you handle error propagation in the Repository?
- What benefits does the Repository provide for offline support?
- Clear abstraction explanation
- Link to clean architecture layers
- Testing advantage
- Skipping mention of data source abstraction
- Explain purpose: abstract data sources
- Show interface with methods
- Detail concrete implementations (remote/local)
- Describe interaction with ViewModel
A legacy project targeted API 21 where Jetpack Navigation wasn't feasible.
Create a lightweight, maintainable navigation system.
Designed a NavigationManager singleton that holds a stack of Fragment tags. Used a sealed class NavCommand (Add, Replace, Pop). Activities called NavigationManager.navigate(command). The manager performed FragmentTransactions with custom animations and handled back‑stack updates. Integrated with ViewModel to preserve state across process death via SavedStateHandle.
Navigation logic was centralized, reduced duplicated transaction code by 70%, and passed code‑review for maintainability.
- Clear architecture
- Handling of back stack
- State preservation
- Ignoring lifecycle implications
- Explain need for custom solution
- Define NavCommand sealed class
- Describe NavigationManager responsibilities
- Show FragmentTransaction handling
- Mention back‑stack and state preservation
Testing & Debugging
Our team needed reliable unit tests for business logic without Android dependencies.
Set up a testing approach for ViewModels.
Used JUnit5 with Kotlin Coroutines Test library. Injected a FakeRepository into the ViewModel. Leveraged LiveDataTestUtil or Turbine to collect Flow emissions. Mocked Android components with Mockito‑Kotlin where necessary. Ran tests on the JVM, not on an emulator.
Achieved 85% unit test coverage for ViewModels, catching regressions early and reducing UI‑related bugs by 30%.
- How do you test ViewModel with SavedStateHandle?
- What is the role of InstantTaskExecutorRule?
- Use of proper testing libraries
- Isolation from Android framework
- Verification of state changes
- Attempting to run Android instrumentation tests for pure unit logic
- Use JUnit5 + coroutine test rule
- Inject fake or mock repositories
- Test LiveData/Flow emissions
- Avoid Android framework classes
A feature required clicking a list item to open a detail screen, and we needed an automated UI test.
Write an Espresso test that verifies the navigation and UI content.
Implemented a test with ActivityScenarioRule. Used onView(withId(R.id.recyclerView)).perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(2, click())). Then asserted that the detail TextView displayed the correct title using onView(withId(R.id.detailTitle)).check(matches(withText(expectedTitle))). Added IdlingResource for asynchronous data loading.
The test reliably caught a regression where the wrong item was passed, preventing a UI bug from reaching production.
- How do you handle flaky tests caused by animations?
- What is the purpose of IdlingResource?
- Correct use of RecyclerViewActions
- Synchronization handling
- Hard‑coding view positions without waiting for data
- Launch activity with ActivityScenarioRule
- Perform click on RecyclerView item using RecyclerViewActions
- Add IdlingResource if data loads async
- Assert UI change with onView and matches
Our app’s memory usage kept growing after navigating between screens, leading to OOM crashes on low‑end devices.
Identify and fix the leak.
Connected Android Studio Profiler to capture heap dumps. Used the LeakCanary library to pinpoint a static singleton holding a reference to an Activity context via a non‑static inner class. Refactored the singleton to use Application context and made the inner class static. Added WeakReference where appropriate and removed unnecessary listeners in onDestroy.
Memory usage stabilized, leak reports disappeared, and crash rate dropped by 90% on affected devices.
- What are the risks of using Application context for UI components?
- How does LeakCanary report a leak?
- Tool usage
- Root cause analysis
- Correct mitigation steps
- Suggesting to ignore the leak
- Use Profiler or LeakCanary to detect leak
- Identify static reference holding Activity context
- Replace with Application context or WeakReference
- Remove listeners in lifecycle callbacks
Our product needed to meet accessibility standards for a government contract.
Implement and verify accessibility features across the app.
Added contentDescription to all ImageViews, used TalkBack to navigate the UI, ensured proper focus order with android:focusable, and provided scalable text via sp units. Leveraged Android Accessibility Test Framework (ATF) in CI to detect missing labels. Conducted manual testing with TalkBack and screen magnifier, and fixed contrast issues using the Material Design color guidelines.
App passed the accessibility audit, received certification, and user satisfaction scores for accessibility improved by 25%.
- What is the role of android:importantForAccessibility?
- How do you test color contrast programmatically?
- Coverage of key accessibility aspects
- Tool integration
- Ignoring TalkBack testing
- Add contentDescription, labels, and hints
- Use TalkBack for manual testing
- Run ATF lint checks in CI
- Ensure proper focus order and contrast
- Kotlin
- Java
- Android SDK
- Jetpack
- MVVM
- Coroutines
- Retrofit
- Room
- Dagger
- Hilt
- LiveData
- ViewModel
- RecyclerView
- Performance
- Testing
- CI/CD