Android Interview Question And Answer
1. What is Android?
Android is an open-source, Linux-based operating system designed primarily for touchscreen mobile devices like smartphones and tablets. Originally developed by Android Inc. (founded by Andy Rubin in 2003), it was later acquired by Google.
2. Android Architecture Layers
The Android stack consists of five key layers:
Linux Kernel - Handles hardware drivers and system security
Libraries - Includes SQLite, WebKit, and media libraries
Android Runtime - Features Dalvik/ART virtual machine
Application Framework - Provides high-level services like Activity Manager
Applications - User-facing apps like Contacts and Browser
3. Android App Components
Every Android app comprises:
Activities (UI screens)
Services (background processes)
Broadcast Receivers (event handlers)
Content Providers (data sharing)
Intents (component communication)
Android Advantages & Limitations
4. Advantages of Android
✔ Open-source platform
✔ Supports multiple programming languages (Kotlin/Java)
✔ Extensive device compatibility
✔ Rich development tools (Android Studio)
✔ Vibrant app ecosystem (Google Play)
5. Disadvantages of Android
❌ Fragmentation across devices/versions
❌ Higher security risks than iOS
❌ Potential for bloatware
❌ Inconsistent update delivery
Development Tools & Techniques
6. ADB vs DDMS
| ADB | DDMS |
|---|---|
| Command-line debug tool | Graphical debug interface |
| Installs APKs | Monitors memory/threads |
| Shell access | Screen capture capability |
7. Essential Languages
Kotlin (Recommended)
Java
C++ (for NDK development)
XML (UI layouts)
8. Activity Lifecycle
onCreate() → onStart() → onResume() → onPause() → onStop() → onDestroy()
Advanced Topics
9. ViewModel & LiveData
ViewModel: Preserves UI data during configuration changes
LiveData: Lifecycle-aware observable data holder
10. Dependency Injection
Hilt simplifies DI in Android:
@HiltAndroidApp class MyApp : Application()
11. Jetpack Compose Benefits
✔ Declarative UI paradigm
✔ Real-time previews
✔ Less boilerplate code
12. Secure Storage Options
EncryptedSharedPreferences
Room Database with encryption
Android Keystore for credentials
Performance Optimization
13. Battery Optimization
Use WorkManager for background tasks
Batch network requests
Optimize location updates
14. Memory Management
Avoid static Context references
Use WeakReference for large objects
Profile with LeakCanary
15. Network Handling
Best practices:
✔ Use Retrofit + Coroutines
✔ Implement caching (OkHttp)
✔ Set proper timeouts
Architecture Patterns
16. MVVM vs MVC
| MVVM | MVC |
|---|---|
| View ↔ ViewModel ↔ Model | View ↔ Controller ↔ Model |
| Data Binding support | Manual UI updates |
17. Repository Pattern
Rapid-Fire Q&A
18. What is a Toast?
→ Short non-interactive message (e.g., "File saved")
19. SQLite in Android?
→ Lightweight embedded database
20. JobScheduler purpose?
→ Optimizes background task execution
21. MotionLayout?
→ Creates complex animations via XML
22. Deep Linking?
→ Directs users to specific app content via URLs
Troubleshooting
23. Common Crash Causes
Memory leaks
Null pointer exceptions
UI thread blocking
Compatibility issues
24. Debugging Tools
Android Studio Profiler
Logcat
StrictMode
System Components Deep Dive
25. Services vs Broadcast Receivers
| Services | Broadcast Receivers |
|---|---|
| Long-running background operations | Short-lived system event responses |
| No UI component | No UI component |
| Started via startService() or bindService() | Triggered by system/intent events |
Example Service Implementation:
class MyService : Service() { override fun onBind(intent: Intent?): IBinder? = null override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { // Background task logic return START_STICKY } }
UI Development Essentials
26. Fragments vs Activities
| Fragments | Activities |
|---|---|
| Modular UI components | Full screen components |
| Reusable across activities | Typically single-purpose |
| Own lifecycle but host-dependent | Independent lifecycle |
Fragment Lifecycle Methods:
onAttach() → onCreate() → onCreateView() → onActivityCreated() → onStart() → onResume() → onPause() → onStop() → onDestroyView() → onDestroy()
27. ConstraintLayout Benefits
✔ Flat view hierarchy (better performance)
✔ Flexible positioning with constraints
✔ Responsive design for all screen sizes
✔ Visual editor in Android Studio
Storage & Database Solutions
28. Room Database Components
Entity - Defines database tables
DAO (Data Access Object) - Contains database operations
Database - Main access point to persisted data
Example Entity:
@Entity(tableName = "users") data class User( @PrimaryKey val id: Int, @ColumnInfo(name = "name") val userName: String )
29. SharedPreferences Best Practices
Use for small key-value pairs
Consider EncryptedSharedPreferences for sensitive data
Avoid storing complex data structures
Networking & APIs
30. Retrofit with Coroutines
interface ApiService { @GET("users") suspend fun getUsers(): List<User> } // Usage viewModelScope.launch { try { val users = apiService.getUsers() } catch (e: Exception) { // Handle error } }
31. OkHttp Interceptors Use Cases
Adding auth headers
Request/response logging
Caching strategies
Error handling
Security Essentials
32. ProGuard vs R8
Both perform:
✓ Code shrinking
✓ Optimization
✓ Obfuscation
Key Difference:
R8 is faster and designed specifically for Android
33. Secure Communication Practices
✔ Always use HTTPS
✔ Implement certificate pinning
✔ Use Android Network Security Config
✔ Sanitize all user inputs
Testing Strategies
34. Unit vs Instrumentation Tests
| Unit Tests | Instrumentation Tests |
|---|---|
| JVM-local tests | Require device/emulator |
| Test business logic | Test UI interactions |
| Fast execution | Slower execution |
35. Popular Testing Libraries
JUnit - Basic unit testing
MockK - Mocking framework
Espresso - UI testing
UI Automator - Cross-app testing
Build System & CI/CD
36. Gradle Build Script Structure
app/ ├── build.gradle (Module-level) └── src/ project/ └── build.gradle (Project-level)
37. CI/CD Pipeline Steps
Code commit → 2. Static analysis → 3. Unit tests →
Build APK → 5. Instrumentation tests → 6. Deploy to testers
Emerging Technologies
38. Jetpack Compose State Management
val count = remember { mutableStateOf(0) } Button(onClick = { count.value++ }) { Text("Clicked ${count.value} times") }
39. Android KMM (Kotlin Multiplatform Mobile)
Shared business logic across iOS/Android
Platform-specific UI layers
Growing adoption in 2024
Behavioral Questions
40. Common Team Scenario Questions
"How do you handle disagreements about architecture?"
"Describe your code review process"
"How do you prioritize technical debt?"
Advanced Android Concepts
41. What is Dependency Injection in Android?
Dependency Injection (DI) is a design pattern where objects receive their dependencies from an external source rather than creating them internally. In Android:
Benefits:
✔ Easier testing and maintenance
✔ Reduced boilerplate code
✔ Loose coupling between components
Implementation Options:
Dagger/Hilt (Recommended)
Koin
Manual DI
Example with Hilt:
@Module @InstallIn(SingletonComponent::class) object AppModule { @Provides fun provideRetrofit(): Retrofit { return Retrofit.Builder() .baseUrl("https://api.example.com/") .build() } }
42. Explain WorkManager in Android
WorkManager is part of Android Jetpack for managing deferrable background work:
Key Features:
Guaranteed execution (even after app restart)
Works with Doze mode restrictions
Supports chained tasks
Backward compatible to API 14
Use Cases:
Periodic syncs
Log uploads
Database maintenance
Example:
val uploadWork = OneTimeWorkRequestBuilder<UploadWorker>() .setConstraints( Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build() ) .build() WorkManager.getInstance(context).enqueue(uploadWork)
Performance Optimization
43. How to Reduce APK Size?
Strategies:
Enable code shrinking (ProGuard/R8)
Use WebP instead of PNG
Remove unused resources
Split APKs by architecture
Use Android App Bundle
Limit library dependencies
Implementation:
android { buildTypes { release { minifyEnabled true shrinkResources true } } }
44. Memory Optimization Techniques
Use memory-efficient collections:
SparseArrayinstead ofHashMap<Integer, Object>ArrayMapfor small collections
Implement proper lifecycle management
Load large bitmaps efficiently:
val options = BitmapFactory.Options().apply { inSampleSize = 2 // Downsample by factor of 2 } val bitmap = BitmapFactory.decodeFile(path, options)
Avoid memory leaks:
Never store Context/View statically
Unregister broadcast receivers
Use WeakReference when needed
Security Best Practices
45. Securing Android Apps
Network Security:
Use HTTPS with certificate pinning
<network-security-config> <domain-config> <domain includeSubdomains="true">example.com</domain> <pin-set> <pin digest="SHA-256">7HIpactk...</pin> </pin-set> </domain-config> </network-security-config>
Data Storage:
Use EncryptedSharedPreferences for small data
Use Room with SQLCipher for encrypted databases
Authentication:
Implement biometric authentication
Use OAuth2 with PKCE for web flows
Code Protection:
Enable ProGuard/R8 obfuscation
Consider using the SafetyNet API
Testing in Android
46. Unit Testing vs Instrumentation Testing
| Aspect | Unit Tests | Instrumentation Tests |
|---|---|---|
| Execution | On JVM (local machine) | On device/emulator |
| Speed | Fast (ms) | Slow (seconds) |
| Dependencies | Mocked | Real implementations |
| Best for | Business logic | UI flows |
Example Unit Test (ViewModel):
@Test fun `validate user input`() { val viewModel = MyViewModel() viewModel.validateInput("test@example.com") assertTrue(viewModel.isInputValid.value) }
Example Instrumentation Test:
@RunWith(AndroidJUnit4::class) class LoginActivityTest { @Test fun login_withValidCredentials() { onView(withId(R.id.email)).perform(typeText("user@test.com")) onView(withId(R.id.password)).perform(typeText("password")) onView(withId(R.id.login_button)).perform(click()) onView(withText("Welcome")).check(matches(isDisplayed())) } }
Kotlin Coroutines in Android
47. Coroutines vs RxJava
| Feature | Coroutines | RxJava |
|---|---|---|
| Learning Curve | Easier | Steeper |
| Backpressure | Manual handling | Built-in support |
| Cancellation | Structured concurrency | Manual disposal |
| Threading | Dispatchers (IO, Main) | Schedulers |
Coroutine Example:
viewModelScope.launch { try { val data = withContext(Dispatchers.IO) { repository.fetchData() } _uiState.value = UiState.Success(data) } catch (e: Exception) { _uiState.value = UiState.Error(e) } }
Jetpack Compose
48. Key Compose Concepts
Composable Functions:
@Composable fun Greeting(name: String) { Text(text = "Hello $name!") }
State Management:
val count = remember { mutableStateOf(0) } Button(onClick = { count.value++ }) { Text("Count: ${count.value}") }
Theming:
MaterialTheme( colors = darkColors(), typography = Typography(), shapes = Shapes() ) { // App content }
Common Interview Challenges
49. Solve This: Activity Launch Modes
Scenario: You need to implement a login flow where:
LoginActivity should always create new instance
HomeActivity should be single instance
SettingsActivity should reuse if on top
Solution:
<activity android:name=".LoginActivity" android:launchMode="standard"/> <activity android:name=".HomeActivity" android:launchMode="singleInstance"/> <activity android:name=".SettingsActivity" android:launchMode="singleTop"/>
50. Debug This: Memory Leak
Problem Code:
class LeakyActivity : AppCompatActivity() { companion object { var leakedContext: Context? = null } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) leakedContext = this } }
Advanced Architecture Patterns
51. Explain Clean Architecture in Android
Clean Architecture organizes code into concentric layers with dependency rules:
Layers:
Domain (Business logic, entities)
Data (Repositories, data sources)
Presentation (UI, ViewModels)
Key Principles:
Dependency Rule: Inner layers don't know about outer layers
Testability: Business logic independent of frameworks
Maintainability: Clear separation of concerns
Implementation Example:
app/
├── domain/
│ ├── entities/
│ ├── repositories/
│ └── usecases/
├── data/
│ ├── local/
│ ├── remote/
│ └── repositories/
└── presentation/
├── activities/
├── fragments/
└── viewmodels/52. MVI vs MVVM
| Aspect | MVI | MVVM |
|---|---|---|
| Data Flow | Unidirectional | Bidirectional |
| State | Immutable | Mutable LiveData |
| Predictability | High (single source) | Medium |
| Learning Curve | Steeper | Easier |
MVI Example:
sealed class MainState { object Loading : MainState() data class Success(val data: List<Item>) : MainState() data class Error(val message: String) : MainState() } class MainViewModel : ViewModel() { private val _state = MutableStateFlow<MainState>(MainState.Loading) val state: StateFlow<MainState> = _state fun loadData() { viewModelScope.launch { _state.value = MainState.Loading try { val data = repository.getData() _state.value = MainState.Success(data) } catch (e: Exception) { _state.value = MainState.Error(e.message ?: "Error") } } } }
Database & Caching Strategies
53. Room Database Migration
Scenario: You need to add a new column to an existing table
Solution:
Update your Entity:
@Entity(tableName = "users") data class User( @PrimaryKey val id: Int, val name: String, val age: Int // New column )
Create migration:
val MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { database.execSQL("ALTER TABLE users ADD COLUMN age INTEGER NOT NULL DEFAULT 0") } }
Add to database builder:
@Database(entities = [User::class], version = 2) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao companion object { fun build(context: Context) = Room.databaseBuilder( context, AppDatabase::class.java, "app-db" ).addMigrations(MIGRATION_1_2) .build() } }
54. Implementing Cache Policy
Network-First Strategy Example:
class DataRepository( private val remote: RemoteDataSource, private val local: LocalDataSource ) { suspend fun getData(): List<Data> { try { val remoteData = remote.getData() local.saveData(remoteData) return remoteData } catch (e: Exception) { return local.getData() // Fallback to cache } } }
Time-Based Cache Invalidation:
const val CACHE_EXPIRY_TIME_MS = 24 * 60 * 60 * 1000 // 24 hours suspend fun getDataWithExpiry(): List<Data> { val cachedData = local.getDataWithTimestamp() return if (System.currentTimeMillis() - cachedData.timestamp < CACHE_EXPIRY_TIME_MS) { cachedData.data } else { val freshData = remote.getData() local.saveDataWithTimestamp(freshData) freshData } }
Advanced UI Techniques
55. Custom View Performance Optimization
Best Practices:
Avoid invalidate() in onDraw()
Use Canvas efficiently:
override fun onDraw(canvas: Canvas) { // Re-use objects paint.color = Color.RED canvas.drawCircle(centerX, centerY, radius, paint) // Avoid allocations // BAD: val path = Path() // GOOD: path.reset() and reuse }
Implement custom attributes:
<declare-styleable name="CustomView"> <attr name="customColor" format="color"/> </declare-styleable>
init { context.obtainStyledAttributes(attrs, R.styleable.CustomView).use { customColor = it.getColor(R.styleable.CustomView_customColor, Color.BLACK) } }
56. Accessibility in Android
Implementation Checklist:
Content descriptions:
<ImageView
android:contentDescription="@string/desc_profile_photo"/>Touch targets (minimum 48dp)
Keyboard navigation:
view.isFocusable = true view.isFocusableInTouchMode = true
TalkBack support:
<Button
android:importantForAccessibility="yes"
android:accessibilityTraversalBefore="@id/next_field"/>Color contrast (minimum 4.5:1 ratio)
Performance Monitoring
57. Using Baseline Profiles
Baseline profiles improve app startup and runtime performance by pre-compiling critical code paths.
Implementation Steps:
Generate profile:
./gradlew :app:generateBaselineProfile
Add dependency:
dependencies { implementation("androidx.profileinstaller:profileinstaller:1.3.1") }
Verify improvements using Macrobenchmark library
58. Identifying Jank with FrameMetrics
window.addOnFrameMetricsAvailableListener({ window, frameMetrics, _ -> val totalDuration = frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION) if (totalDuration > 16) { // >16ms means dropped frame logJankyFrame(totalDuration) } }, Handler())
Advanced Dependency Injection
59. Dynamic Feature DI with Hilt
Feature Module Setup:
@Module @InstallIn(ViewModelComponent::class) object FeatureModule { @Provides fun provideFeatureDependency(): FeatureDependency { return RealFeatureDependency() } }
Activity in Dynamic Feature:
@AndroidEntryPoint class FeatureActivity : AppCompatActivity() { @Inject lateinit var featureDependency: FeatureDependency }
60. Qualifiers in Hilt
@Module @InstallIn(SingletonComponent::class) object NetworkModule { @AuthInterceptor @Provides fun provideAuthRetrofit(): Retrofit { /*...*/ } @PublicInterceptor @Provides fun providePublicRetrofit(): Retrofit { /*...*/ } } // Usage class Repository @Inject constructor( @AuthInterceptor private val authRetrofit: Retrofit, @PublicInterceptor private val publicRetrofit: Retrofit )
Security Deep Dive
61. Implementing Biometric Authentication
val promptInfo = BiometricPrompt.PromptInfo.Builder() .setTitle("Login") .setSubtitle("Authenticate to continue") .setNegativeButtonText("Use password") .build() val biometricPrompt = BiometricPrompt( activity, ContextCompat.getMainExecutor(activity), object : BiometricPrompt.AuthenticationCallback() { override fun onAuthenticationSucceeded(result: AuthenticationResult) { // Handle success } } ) biometricPrompt.authenticate(promptInfo)
62. Secure SharedPreferences
val masterKey = MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() val sharedPreferences = EncryptedSharedPreferences.create( context, "secret_prefs", masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM )
Emerging Technologies
63. Jetpack Compose Navigation
Setup:
@Composable fun AppNavigation() { val navController = rememberNavController() NavHost(navController, startDestination = "home") { composable("home") { HomeScreen(navController) } composable("details/{id}") { backStackEntry -> DetailsScreen(backStackEntry.arguments?.getString("id")) } } }
Navigation:
navController.navigate("details/$itemId")
64. Android TV Development Considerations
Focus Handling:
Modifier.focusable() .onFocusChanged { focusState -> scale = if (focusState.isFocused) 1.1f else 1f }
Leanback Library Components:
BrowseFragment
DetailsFragment
PlaybackControlsFragment
Input Device Support:
view.setOnKeyListener { _, keyCode, event -> if (event.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { // Handle select true } else false }
This collection now covers advanced architecture patterns, performance optimization, security, and emerging technologies. Would you like me to:
Comments
Post a Comment