0% found this document useful (0 votes)
13 views36 pages

5-Day Android Interview Prep Guide

This document outlines a 5-day intensive preparation plan for a Google Senior Software Engineer interview focused on Android development. Each day is structured with specific topics covering Kotlin, Android components, architecture patterns, Jetpack components, system design, and practical projects. The plan emphasizes hands-on exercises, critical concepts, and interview questions to ensure comprehensive readiness for the interview rounds.

Uploaded by

Hk Xicor
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views36 pages

5-Day Android Interview Prep Guide

This document outlines a 5-day intensive preparation plan for a Google Senior Software Engineer interview focused on Android development. Each day is structured with specific topics covering Kotlin, Android components, architecture patterns, Jetpack components, system design, and practical projects. The plan emphasizes hands-on exercises, critical concepts, and interview questions to ensure comprehensive readiness for the interview rounds.

Uploaded by

Hk Xicor
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

5-Day Intensive Android Interview Prep Plan for Google Senior Software

Engineer

Overview
This is an aggressive, comprehensive plan to prepare for Google's Android Senior Software Engineer interview
in 5 days. The plan assumes 16-18 hours of focused study per day (with breaks for sleep/rest).

Interview Rounds You're Preparing For:

1. DSA (You're managing separately)

2. Android Technical Interview

3. Hands-on Android Project Round

DAY 1: Kotlin Fundamentals + Core Android Components (18 hours)

Morning Session (6 hours): Kotlin Deep Dive

Part 1: Kotlin Basics (2 hours)

Variables & Types: val vs var, const val, lateinit, lazy

Functions: Higher-order functions, extension functions, infix functions

Null Safety: Nullable types, safe calls (?.), elvis operator (?:), !! operator

Data Classes: Auto-generated methods, copy(), destructuring

Sealed Classes & Objects: When to use, companion objects

Lambda Expressions: Syntax, trailing lambdas, with/apply/let/run/also

Practice Exercise:

kotlin
// Create a data class for User with validation
data class User(val name: String, val email: String) {
init {
require([Link]("@")) { "Invalid email" }
}
}

// Extension function example


fun [Link]() = contains("@") && contains(".")

// Higher-order function
fun processUser(user: User, action: (User) -> Unit) {
action(user)
}

Part 2: Kotlin Coroutines (4 hours) CRITICAL

Must-Know Concepts:

Structured Concurrency

Coroutine Scopes: GlobalScope, lifecycleScope, viewModelScope, coroutineScope

Dispatchers: Main, IO, Default, Unconfined

Launch vs Async/Await

suspend functions

Job, Deferred

Exception Handling in Coroutines

Coroutine Context

Key Interview Questions:

1. Difference between launch and async?

2. What happens if exception is thrown in async but await() is never called?

3. How to run coroutines in parallel vs sequential?

4. Explain structured concurrency

5. What is SupervisorJob?

Hands-on Exercise:

kotlin
// Sequential execution
suspend fun fetchUserData() {
val user = fetchUser() // Waits
val posts = fetchPosts() // Waits after user
}

// Parallel execution
suspend fun fetchUserDataParallel() = coroutineScope {
val userDeferred = async { fetchUser() }
val postsDeferred = async { fetchPosts() }
Pair([Link](), [Link]())
}

// Exception handling
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught: $exception")
}

Afternoon Session (6 hours): Core Android Components

Android Application Components (3 hours)

Activities:

Activity Lifecycle (onCreate → onStart → onResume → onPause → onStop → onDestroy)

onSaveInstanceState & onRestoreInstanceState

Launch Modes: standard, singleTop, singleTask, singleInstance

Task & Back Stack management

Configuration changes handling

Fragments:

Fragment Lifecycle vs Activity Lifecycle

Fragment Transactions & BackStack

Fragment communication (ViewModel, Interfaces)

FragmentContainerView

Why use fragments?

Services:

Foreground Service vs Background Service


Started Service vs Bound Service

IntentService (deprecated, use WorkManager)

Service lifecycle

Broadcast Receivers:

Static vs Dynamic registration

LocalBroadcastManager

Ordered broadcasts

Content Providers:

CRUD operations

ContentResolver

URI matching

When to use?

Key Interview Questions:

1. Activity lifecycle when opening another activity

2. Difference between onPause and onStop

3. When is onDestroy() not called?

4. How to handle process death?

5. Fragment vs Activity - when to use which?

6. Launch modes practical scenarios

7. Service vs IntentService vs WorkManager

Intents & Navigation (1.5 hours)

Explicit vs Implicit Intents

Intent Filters

PendingIntent

Deep Links & App Links

Navigation Component (Jetpack)

Android Manifest (0.5 hours)


Essential tags and attributes

Permissions (runtime vs install-time)

Application class

Evening Session (6 hours): First Practice Project

Project 1: News Reader App (6 hours) Build a news app using:

Kotlin + Coroutines

MVVM Architecture (prepare for Day 2)

RecyclerView with DiffUtil

Multiple Activities/Fragments

Proper lifecycle handling

Requirements:

List of news articles

Detail screen

Handle rotation properly

Loading states

Error handling

DAY 2: Architecture Patterns + Jetpack Components (18 hours)

Morning Session (6 hours): MVVM Architecture GOOGLE FAVORITE

MVVM Deep Dive (4 hours)

Components:

1. Model: Data layer (Repository, Data Sources, API, Database)

2. View: UI Layer (Activity/Fragment/Compose)

3. ViewModel: Business logic, state management

Key Concepts:

ViewModel lifecycle awareness


ViewModelFactory

LiveData vs StateFlow vs SharedFlow

Repository Pattern

Single Source of Truth

Unidirectional Data Flow

LiveData vs Flow vs StateFlow:

kotlin

// LiveData - lifecycle aware, always has value


val userData: LiveData<User> = MutableLiveData()

// StateFlow - always has value, Kotlin Flow + State


val userData: StateFlow<User> = MutableStateFlow(User())

// SharedFlow - can be hot, no initial value needed


val events: SharedFlow<Event> = MutableSharedFlow()

// Flow - cold stream, reactive


fun getUsers(): Flow<List<User>> = flow {
emit([Link]())
}

Must Practice:

Converting callbacks to Flow/LiveData

Combining multiple data sources

Error handling in ViewModels

Testing ViewModels

Clean Architecture (2 hours)

Layers:

1. Presentation Layer: UI + ViewModel

2. Domain Layer: Use Cases, Business Logic, Domain Models

3. Data Layer: Repository, Data Sources, DTOs

Benefits:

Testability
Separation of concerns

Independence from frameworks

Scalability

Key Interview Questions:

1. Why MVVM over MVP/MVC?

2. How to communicate between ViewModel and View?

3. ViewModel vs AndroidViewModel

4. How to share ViewModel between fragments?

5. Explain Single Source of Truth

6. When to use LiveData vs Flow?

7. How to handle configuration changes in MVVM?

Afternoon Session (6 hours): Jetpack Components

Room Database (2 hours) CRITICAL

Components:

Entity (Table)

DAO (Data Access Object)

Database (Singleton)

Must Know:

Relationships (@Relation, @Embedded)

Migrations

Type Converters

Transactions

Flow + Room for reactive queries

[Link]

kotlin
@Entity(tableName = "users")
data class UserEntity(
@PrimaryKey val id: Int,
@ColumnInfo(name = "user_name") val name: String
)

@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getAllUsers(): Flow<List<UserEntity>>

@Insert(onConflict = [Link])
suspend fun insert(user: UserEntity)

@Transaction
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getUserWithPosts(userId: Int): UserWithPosts
}

@Database(entities = [UserEntity::class], version = 1)


abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao

companion object {
@Volatile private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase =
INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
}
}

Retrofit + Networking (1.5 hours)

REST API calls

Converters (Gson, Moshi, Kotlinx Serialization)

Interceptors (OkHttp)

Error handling

Suspend functions with Retrofit

Combining with Coroutines/Flow

kotlin
interface ApiService {
@GET("users/{id}")
suspend fun getUser(@Path("id") id: Int): Response<User>

@POST("users")
suspend fun createUser(@Body user: User): Response<User>
}

// Repository
class UserRepository(private val api: ApiService) {
suspend fun getUser(id: Int): Result<User> {
return try {
val response = [Link](id)
if ([Link]) {
[Link]([Link]()!!)
} else {
[Link](Exception([Link]()))
}
} catch (e: Exception) {
[Link](e)
}
}
}

WorkManager (1 hour)

For deferrable background work

Constraints (network, charging, etc.)

OneTimeWorkRequest vs PeriodicWorkRequest

Chaining work

WorkManager vs JobScheduler vs AlarmManager

Paging 3 Library (1 hour)

PagingSource

Paging with Room

RemoteMediator

Load states

Navigation Component (0.5 hours)


NavGraph, NavHost, NavController

Safe Args

Deep linking

Evening Session (6 hours): Project 2 - Advanced Architecture

Project 2: Task Manager App (6 hours) Build with:

MVVM + Clean Architecture

Room Database

Retrofit API (use JSONPlaceholder)

Repository Pattern

Flow/StateFlow

Coroutines

WorkManager for sync

Features:

CRUD operations

Offline-first approach

Pull to refresh

Search functionality

Proper error handling

DAY 3: Jetpack Compose + Modern UI (18 hours)

Morning Session (6 hours): Jetpack Compose Fundamentals MUST KNOW

Compose Basics (3 hours)

Core Concepts:

Declarative UI vs Imperative UI

Composable functions (@Composable)

Composition vs Recomposition

State & State Hoisting


remember, rememberSaveable

Modifier system

Layouts: Column, Row, Box, LazyColumn, LazyRow

State Management:

kotlin

@Composable
fun Counter() {
// State that survives recomposition
var count by remember { mutableStateOf(0) }

// State that survives process death


var count2 by rememberSaveable { mutableStateOf(0) }

Column {
Text("Count: $count")
Button(onClick = { count++ }) {
Text("Increment")
}
}
}

// State hoisting
@Composable
fun StatelessCounter(
count: Int,
onIncrement: () -> Unit
){
Button(onClick = onIncrement) {
Text("Count: $count")
}
}

Side Effects in Compose (2 hours) CRITICAL FOR INTERVIEWS

Must Master:

1. LaunchedEffect: For suspend functions

2. DisposableEffect: Setup/cleanup (like useEffect in React)

3. SideEffect: Publish state to non-compose code

4. derivedStateOf: Computed state

5. rememberCoroutineScope: Manual coroutine launch


6. rememberUpdatedState: Capture latest value in callback

kotlin

// LaunchedEffect - runs when key changes


LaunchedEffect(userId) {
val user = [Link](userId)
// Update state
}

// DisposableEffect - cleanup needed


DisposableEffect(Unit) {
val listener = LocationListener()
[Link](listener)

onDispose {
[Link](listener)
}
}

// rememberCoroutineScope - for event handlers


val scope = rememberCoroutineScope()
Button(onClick = {
[Link] {
[Link]("Message")
}
}) {
Text("Show Snackbar")
}

// derivedStateOf - expensive computation


val filteredList by remember {
derivedStateOf {
[Link] { [Link] }
}
}

Compose Performance (1 hour)

Avoiding unnecessary recompositions

Key parameter in lists

Stability in Compose

Immutable collections

@Stable and @Immutable annotations


Afternoon Session (6 hours): Advanced Compose

Compose + ViewModel (2 hours)

kotlin

@Composable
fun UserScreen(viewModel: UserViewModel = viewModel()) {
val uiState by [Link]()

when (uiState) {
is Loading -> LoadingScreen()
is Success -> UserList([Link])
is Error -> ErrorScreen([Link])
}
}

// ViewModel
class UserViewModel : ViewModel() {
private val _uiState = MutableStateFlow<UiState>(Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()

init {
loadUsers()
}

private fun loadUsers() {


[Link] {
try {
val users = [Link]()
_uiState.value = Success(users)
} catch (e: Exception) {
_uiState.value = Error([Link])
}
}
}
}

Material Design 3 in Compose (1 hour)

Material Theme

Colors, Typography, Shapes

Material Components

Dark theme support


Lists & Performance (2 hours)

LazyColumn vs Column

LazyVerticalGrid

Sticky headers

Item animations

Keys in lists

Navigation in Compose (1 hour)

NavHost, NavController

Passing arguments

Bottom navigation

Nested navigation

Evening Session (6 hours): Project 3 - Compose App

Project 3: E-commerce Product Catalog (6 hours) Build with:

100% Jetpack Compose

MVVM Architecture

StateFlow/Flow

Navigation Compose

Material Design 3

LazyColumn with pagination

Search & Filter

Detail screen with animations

DAY 4: System Design + Advanced Topics (18 hours)

Morning Session (6 hours): Android System Design CRITICAL FOR GOOGLE

System Design Approach (1 hour)

Steps:
1. Clarify requirements (5 min)

2. High-level design (10 min)

3. Component design (15 min)

4. Deep dive into critical components (15 min)

5. Trade-offs & Optimizations (10 min)

Common Questions:

1. Design WhatsApp

2. Design Instagram

3. Design News Reader App

4. Design File Download Manager

5. Design Stopwatch (Google asked this!)

6. Design Image Loading Library

7. Design Analytics Library

System Design Practice (5 hours)

Problem 1: Design WhatsApp (2 hours)

Requirements:

Send/receive text messages

Online/offline status

Message delivery status (sent, delivered, read)

Offline support

Real-time updates

Solution Outline:
Architecture: MVVM + Clean Architecture

Layers:
├── Presentation (Compose/XML + ViewModel)
├── Domain (UseCases)
└── Data
├── Repository
├── Local (Room Database)
└── Remote (WebSocket + REST API)

Key Components:

1. Data Layer:
- WebSocket for real-time messaging
- REST API for historical messages
- Room DB for offline storage
- Repository as single source of truth

2. Message Sync:
- WorkManager for background sync
- Exponential backoff for retries
- Conflict resolution strategy

3. Message States:
- Pending (storing locally)
- Sent (delivered to server)
- Delivered (user received)
- Read (user opened)

4. Online/Offline:
- ConnectivityManager + NetworkCallback
- Ping/pong mechanism via WebSocket
- Update UI based on connection state

5. Performance:
- Pagination for message history
- Message batching
- DB indexing
- Message pooling

Database Schema:
@Entity
data class Message(
@PrimaryKey val id: String,
val senderId: String,
val receiverId: String,
val content: String,
val timestamp: Long,
val status: MessageStatus, // PENDING, SENT, DELIVERED, READ
val type: MessageType // TEXT, IMAGE, VIDEO
)

WebSocket Events:
- onMessageReceived
- onMessageStatusUpdate
- onUserOnlineStatus
- onTypingIndicator

Problem 2: Design Instagram Feed (1.5 hours)

Requirements:

Infinite scroll feed

Images/videos

Like, comment, share

Offline support

Preload next page

Key Points:

Paging 3 with RemoteMediator

Image caching (Glide/Coil)

Video playback optimization

Feed ranking algorithm

Database normalization

Problem 3: Design Stopwatch (Google Question!) (1.5 hours)

Requirements:

Start, pause, stop, lap

Millisecond precision

Persist across config changes

No system libraries

Solution:
kotlin
class StopwatchUseCase {
private var startTime = 0L
private var pausedTime = 0L
private var isRunning = false
private val laps = mutableListOf<Long>()

private val _timeFlow = MutableStateFlow(0L)


val timeFlow: StateFlow<Long> = _timeFlow

private var job: Job? = null

fun start() {
if (!isRunning) {
startTime = [Link]() - pausedTime
isRunning = true

job = CoroutineScope([Link]).launch {
while (isRunning) {
_timeFlow.value = [Link]() - startTime
delay(10) // 10ms precision
}
}
}
}

fun pause() {
if (isRunning) {
pausedTime = [Link]() - startTime
isRunning = false
job?.cancel()
}
}

fun stop() {
isRunning = false
pausedTime = 0L
startTime = 0L
_timeFlow.value = 0L
[Link]()
job?.cancel()
}

fun lap() {
[Link](_timeFlow.value)
}
}
// ViewModel
class StopwatchViewModel : ViewModel() {
private val stopwatchUseCase = StopwatchUseCase()

val time = [Link]


.stateIn(
viewModelScope,
[Link](5000),
0L
)

fun start() = [Link]()


fun pause() = [Link]()
fun stop() = [Link]()
}

// In Compose
@Composable
fun StopwatchScreen(viewModel: StopwatchViewModel = viewModel()) {
val time by [Link]()

Column {
Text(formatTime(time))
Row {
Button(onClick = viewModel::start) { Text("Start") }
Button(onClick = viewModel::pause) { Text("Pause") }
Button(onClick = viewModel::stop) { Text("Stop") }
}
}
}

fun formatTime(millis: Long): String {


val seconds = (millis / 1000) % 60
val minutes = (millis / (1000 * 60)) % 60
val hours = millis / (1000 * 60 * 60)
val ms = (millis % 1000) / 10
return "%02d:%02d:%02d.%02d".format(hours, minutes, seconds, ms)
}

Afternoon Session (6 hours): Performance & Optimization

Memory Management (2 hours)

Topics:

Memory Leaks (Handler, Context, static references)


Leak Detection (LeakCanary)

Memory Profiler

Bitmap handling

WeakReference, SoftReference

Memory thrashing

GC types

Common Leaks:

kotlin
// BAD - Memory Leak
class MyActivity : AppCompatActivity() {
companion object {
private var context: Context? = null // LEAK!
}
}

// GOOD - Use Application Context


class MyActivity : AppCompatActivity() {
companion object {
private var context: Context? = null
fun init(app: Application) {
context = [Link]
}
}
}

// BAD - Handler Leak


private val handler = Handler() { // LEAK!
// Handle message
true
}

// GOOD - WeakReference
private class MyHandler(activity: MainActivity) : Handler() {
private val weakActivity = WeakReference(activity)

override fun handleMessage(msg: Message) {


[Link]()?.let {
// Use activity
}
}
}

App Performance (2 hours)

Metrics:

App startup time (cold, warm, hot)

Frame rate (60fps, 120fps)

ANR (Application Not Responding)

Jank/Frame drops

Optimization Techniques:
ViewStub for lazy inflation

RecyclerView optimizations (ViewHolder pattern, DiffUtil, RecycledViewPool)

Avoid overdraw

Use ConstraintLayout over nested layouts

Profile-guided optimization

R8/ProGuard

App Bundle

StrictMode:

kotlin

if ([Link]) {
[Link](
[Link]()
.detectAll()
.penaltyLog()
.build()
)
[Link](
[Link]()
.detectAll()
.penaltyLog()
.build()
)
}

Dependency Injection - Hilt/Dagger (2 hours) IMPORTANT

Hilt Setup:

kotlin
@HiltAndroidApp
class MyApplication : Application()

@AndroidEntryPoint
class MainActivity : AppCompatActivity()

@AndroidEntryPoint
class UserFragment : Fragment()

// Module
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideDatabase(@ApplicationContext context: Context): AppDatabase {
return [Link](
context,
AppDatabase::[Link],
"app_database"
).build()
}

@Provides
fun provideUserDao(database: AppDatabase): UserDao {
return [Link]()
}
}

// ViewModel with Hilt


@HiltViewModel
class UserViewModel @Inject constructor(
private val repository: UserRepository
) : ViewModel() {
// Implementation
}

Evening Session (6 hours): Testing

Unit Testing (2 hours)

JUnit 4/5

Mockito, MockK

Testing ViewModels
Testing Repositories

Coroutine testing (TestCoroutineDispatcher)

kotlin

class UserViewModelTest {
@get:Rule
val instantExecutorRule = InstantTaskExecutorRule()

@get:Rule
val mainDispatcherRule = MainDispatcherRule()

private lateinit var repository: UserRepository


private lateinit var viewModel: UserViewModel

@Before
fun setup() {
repository = mockk()
viewModel = UserViewModel(repository)
}

@Test
fun `loadUsers should update state to Success`() = runTest {
// Given
val users = listOf(User(1, "Test"))
coEvery { [Link]() } returns [Link](users)

// When
[Link]()

// Then
assert([Link] is Success)
assertEquals(users, ([Link] as Success).data)
}
}

UI Testing (2 hours)

Espresso

Compose Testing

UI Automator

Screenshot testing

kotlin
@get:Rule
val composeTestRule = createComposeRule()

@Test
fun counterIncrements() {
[Link] {
Counter()
}

[Link]("0").assertExists()
[Link]("Increment").performClick()
[Link]("1").assertExists()
}

Integration Testing (1 hour)

Testing with real database

Testing API calls

End-to-end testing

Project 4: Implement Tests (1 hour)

Add tests to one of your previous projects.

DAY 5: Advanced Topics + Mock Interviews (18 hours)

Morning Session (6 hours): Advanced Android Topics

Custom Views (2 hours)

kotlin
class CircularProgressBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {


style = [Link]
strokeWidth = 20f
}

var progress = 0f
set(value) {
field = [Link](0f, 100f)
invalidate() // Redraw
}

override fun onDraw(canvas: Canvas) {


[Link](canvas)

val centerX = width / 2f


val centerY = height / 2f
val radius = minOf(centerX, centerY) - [Link]

// Draw background circle


[Link] = [Link]
[Link](centerX, centerY, radius, paint)

// Draw progress arc


[Link] = [Link]
val sweepAngle = (progress / 100f) * 360f
[Link](
centerX - radius,
centerY - radius,
centerX + radius,
centerY + radius,
-90f,
sweepAngle,
false,
paint
)
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {


val size = minOf(
[Link](widthMeasureSpec),
[Link](heightMeasureSpec)
)
setMeasuredDimension(size, size)
}
}

Animations (1 hour)

View animations (Alpha, Scale, Translate, Rotate)

Property animations (ValueAnimator, ObjectAnimator)

Transition framework

MotionLayout

Compose animations

Multi-threading (1 hour)

Threads vs Coroutines

Handler, Looper, HandlerThread

AsyncTask (deprecated)

Executor framework

Thread safety

Security (1 hour)

EncryptedSharedPreferences

Keystore system

Network security config

Certificate pinning

ProGuard/R8 obfuscation

SafetyNet API

Firebase Integration (1 hour)

Cloud Firestore

Firebase Auth

Cloud Messaging (FCM)

Crashlytics
Remote Config

Analytics

Afternoon Session (6 hours): Practice Common Questions

Top 50 Must-Know Interview Questions

Kotlin:

1. val vs var vs const val

2. lateinit vs lazy

3. Higher-order functions

4. Extension functions

5. Sealed classes vs Enum

6. Companion object

7. Data classes

8. inline, noinline, crossinline

9. Scope functions (let, run, with, apply, also)

10. Coroutines fundamentals

Android Components: 11. Activity lifecycle 12. Fragment lifecycle 13. Launch modes 14. Service types 15.
BroadcastReceiver 16. Content Provider 17. Intent types 18. PendingIntent 19. Task affinity 20. Process and
Application

Architecture: 21. MVVM vs MVP vs MVC 22. Repository pattern 23. Clean Architecture 24. Single Source of
Truth 25. Unidirectional data flow 26. ViewModel vs AndroidViewModel 27. LiveData vs Flow vs StateFlow

Jetpack: 28. Room - Entities, DAO, Database 29. Room migrations 30. Room relationships 31. WorkManager
constraints 32. Navigation Component 33. Paging 3 34. DataStore vs SharedPreferences

Compose: 35. Recomposition 36. State hoisting 37. remember vs rememberSaveable 38. LaunchedEffect vs
DisposableEffect 39. derivedStateOf 40. Side effects in Compose

Networking & Data: 41. Retrofit suspend functions 42. OkHttp interceptors 43. Caching strategies 44. Error
handling 45. JSON parsing (Gson, Moshi, Kotlinx)

Performance: 46. Memory leaks 47. ANR causes and prevention 48. RecyclerView optimization 49. Bitmap
handling 50. App startup optimization

Practice: Write detailed answers for each. Use STAR method for behavioral questions.
Evening Session (6 hours): Final Project + Mock Interview

Project 5: Twitter Clone (4 hours) COMPLETE APP

Build a mini Twitter with:

Login/Register (mock API or Firebase)

Feed (LazyColumn)

Post tweet

Like/retweet

Profile screen

MVVM + Clean Architecture

Room for caching

Retrofit for API

Jetpack Compose

Pull to refresh

Proper error handling

Loading states

Dark theme support

Focus on:

System design decisions

Code organization

Handling edge cases

Performance

Testing

Mock Interview (2 hours)

Practice answering:

1. "Design a file download manager"

2. "How would you implement pull-to-refresh?"

3. "Explain your architecture choices in the Twitter app"

4. "How do you handle configuration changes?"


5. "What would you do if users report app crashes?"

Essential Resources

Documentation

Android Developers

Kotlin Docs

Jetpack Compose

GitHub Repositories to Study

amitshekhariitbhu/android-interview-questions

anandwana001/android-interview

Android Architecture Samples

Now in Android

YouTube Channels

Philipp Lackner

Coding in Flow

Android Developers (official)

Google-Specific Tips (Based on Real Experiences)

What Google Actually Asks:

1. System Design is CRITICAL - 2-3 rounds may be system design

2. Stopwatch problem - Design without libraries

3. Thread safety questions

4. Coroutines deep dive

5. Architecture justification

6. Performance optimization scenarios

Interview Tips:
1. Think out loud - Explain your reasoning

2. Ask clarifying questions - Don't jump to coding

3. Discuss trade-offs - No perfect solution

4. Start with high-level design - Then deep dive

5. Be ready to defend choices - "Why MVVM?" "Why Flow over LiveData?"

6. Code quality matters - Clean, readable, maintainable

7. Handle edge cases - Null safety, errors, loading states

8. Know the Android framework deeply - Not just libraries

Red Flags to Avoid:

Not asking questions

Jumping to code immediately

Ignoring error handling

Poor code organization

Not explaining trade-offs

Saying "I don't know" without attempting

Being inflexible about solutions

Green Flags:

Structured approach

Clear communication

Considering scale

Security awareness

Performance consciousness

Testing mindset

Modern Android practices


Quick Reference Cheat Sheet

Coroutines Cheat Sheet

kotlin

// Sequential
val a = async { fetchA() }
val b = async { fetchB() }
[Link]() + [Link]()

// Parallel
coroutineScope {
val a = async { fetchA() }
val b = async { fetchB() }
[Link]() + [Link]()
}

// Dispatchers
[Link] // UI operations
[Link] // Network, DB
[Link] // CPU-intensive
[Link] // Don't use

// Exception handling
supervisorScope {
// Children failures don't cancel parent
}

Room Cheat Sheet

kotlin
// Entity
@Entity(tableName = "users")
data class User(@PrimaryKey val id: Int, val name: String)

// DAO
@Dao interface UserDao {
@Query("SELECT * FROM users") fun getAll(): Flow<List<User>>
@Insert suspend fun insert(user: User)
@Delete suspend fun delete(user: User)
}

// Database
@Database(entities = [User::class], version = 1)
abstract class AppDb : RoomDatabase() {
abstract fun userDao(): UserDao
}

Compose Cheat Sheet

kotlin

// State
var text by remember { mutableStateOf("") }
var text by rememberSaveable { mutableStateOf("") }

// Side effects
LaunchedEffect(key) { /* suspend */ }
DisposableEffect(key) { onDispose { } }
val scope = rememberCoroutineScope()

// Layouts
Column(modifier = Modifier) { }
Row(modifier = Modifier) { }
Box(modifier = Modifier) { }
LazyColumn { items(list) { } }

Final Day Checklist

Before Interview:

Review all 5 projects


Practice explaining system design on whiteboard/paper
Prepare questions for interviewer
Test your setup (if remote)
Get good sleep

During Interview:

Listen carefully
Ask clarifying questions
Think out loud
Start with high-level design
Consider edge cases
Discuss trade-offs
Keep code clean
Handle feedback gracefully

Topics You MUST Be Confident In:

1. Kotlin Coroutines (launch, async, Flow, StateFlow)

2. MVVM Architecture (ViewModel, LiveData, Repository)

3. Jetpack Compose (State, Side effects, Recomposition)

4. Room Database (Entities, DAO, Migrations)

5. System Design (WhatsApp, Instagram, News App)

6. Performance Optimization (Memory, ANR, Rendering)

7. Testing (Unit, UI, Integration)

8. Dependency Injection (Hilt)

Final Words

Remember:

Google values system thinking over memorization

Communication is as important as coding

Trade-offs show maturity

Ask questions - shows you think about requirements

Be honest - if you don't know something, say so but show how you'd learn

You have 5 days. Make them count!

Coming from TypeScript background is actually an advantage:


You understand async patterns (Promises ≈ Coroutines)

You know reactive programming

Modern tooling experience

Strong CS fundamentals transfer

You can do this! Good luck!

Common questions

Powered by AI

Designing a scalable news reader app using the MVVM architecture involves several key components and structured steps. Start by clarifying app requirements, such as articles listing, search, and offline support. The high-level architecture consists of three layers: Presentation, Domain, and Data . In the Presentation layer, use Views like activities or fragments in combination with ViewModels to handle UI logic and state management, ensuring lifecycle awareness . The Domain layer encompasses use cases encapsulating app-specific business logic, while the Data layer involves repositories and APIs to fetch and store articles, utilizing Room for local data caching . The design should incorporate effective use of coroutines for asynchronous operations and Jetpack components like ViewModel and LiveData or Flow for real-time data updates . Moreover, implementing unidirectional data flow and repository patterns ensures a single source of truth, enhancing app scalability and maintainability .

Considering application states such as Pending, Sent, Delivered, and Read is crucial for ensuring a seamless user experience and reliable message delivery status in a messaging app. These states provide transparency to users about the status of their communications . In an MVVM architecture, these states can be effectively managed by using a ViewModel to handle the logic and data-binding processes associated with each state. Implementing a repository pattern allows the system to maintain a single source of truth, synchronizing these states with the server via real-time protocols like WebSocket and handling data persistence with Room for offline scenarios . By coupling ViewModel with LiveData or Flow, state changes can be observed and reflected in the UI efficiently, ensuring up-to-date status information across user interactions and network conditions .

To implement a 'pull-to-refresh' feature in a modern Android application using Jetpack Compose and StateFlow, start by setting up a SwipeRefreshLayout or equivalent composable that recognizes the pull gesture. Integrate a ViewModel with a StateFlow object to manage and emit UI states, including loading, success, and error. Use collectAsState in the composable to observe these state changes . Define an OnRefresh event within the composable that triggers a function in the ViewModel, which fetches new data from the repository or remote API, updating the StateFlow with the result. The UI should display loading indicators based on the StateFlow state, and upon data refresh, the state changes should propagate, re-triggering list composition . This approach ensures a responsive, asynchronous UI update capability that leverages Jetpack Compose’s declarative design and Kotlin's Flow-based state management .

LazyColumn, part of Jetpack Compose, and RecyclerView are both used in Android for displaying large lists of items efficiently. RecyclerView is the older, more established component that supports different view types and has extensive customization through adapters and view holders, which can be a bit verbose . LazyColumn simplifies list development by using Compose's declarative approach, which inherently handles item recomposition and improves performance for dynamic UIs through easier state management and recomposition control . LazyColumn is better suited for modern UI development in Compose, offering performance improvements by leveraging Compose's optimizations, whereas RecyclerView remains more flexible for projects needing extensive feature customization and backward compatibility with existing component infrastructure .

The MVVM architecture ensures separation of concerns by clearly defining roles for each component, enhancing testability, and decoupling the view from the business logic . In MVVM, the Model layer handles the data layer operations, including repositories and data sources that interact with both APIs and databases . The View is responsible for displaying the data on the UI using Activities, Fragments, or Compose, and responds to user interactions . The ViewModel acts as a mediator between the View and the Model, containing the business logic, state management, and UI-related logic while remaining lifecycle-aware . This separation allows each layer to be modified independently, fulfilling its unique role in the application lifecycle.

Network connectivity changes can significantly impact an Android app's performance and user experience by affecting data synchronization, real-time communication, and content availability. In MVVM architecture, these changes can be managed effectively by using a ViewModel to observe connectivity status and coordinate UI logic based on current network conditions . Incorporating ConnectivityManager and NetworkCallback in the Model layer can inform the ViewModel about connectivity updates, while the UI state adjusts accordingly, showing offline modes, cached content, or retry options when appropriate. Integrating reactive programming elements like StateFlow or LiveData ensures the View receives immediate updates related to connectivity, ensuring seamless updates to the user interface . This setup provides resilient network handling, essential for maintaining consistent application behavior across varying connectivity scenarios.

LiveData, StateFlow, and SharedFlow serve different purposes in Android development. LiveData is lifecycle-aware and always holds a value, making it suitable for UI-related data in activities or fragments that require automatic handling of lifecycle changes . StateFlow, like LiveData, also always holds a value but is part of Kotlin's Flow API, supporting reactive programming. It is useful when the app needs to handle state management while allowing for more complex, asynchronous data flows without being tied to the Android lifecycle . SharedFlow, on the other hand, is a hot stream without an initial value and can emit values even when there are no collectors present, which makes it ideal for events that may be triggered once with no initial state requirement or for broadcasting events to multiple subscribers at any time .

Kotlin Coroutines offer several advantages over traditional multithreading approaches like threading and handlers in Android. Coroutines allow for writing asynchronous code in a more sequential and readable manner, reducing the complexity introduced by callbacks and nested code structures . They can suspend operations in a non-blocking way, which helps in efficient resource usage and maintaining smooth UI responsiveness. Additionally, coroutines provide structured concurrency, allowing developers to define scopes that manage the lifecycle of asynchronous tasks, thereby reducing the risk of memory leaks and more predictable cancellation . Their integration with Kotlin's language features enables more concise and expressive code compared to explicit thread management.

An exponential backoff strategy enhances the robustness of background processing by spacing out retry attempts to avoid overloading resources when initial attempts fail due to temporary issues like network fluctuations. In the WorkManager framework, this strategy starts with a short delay between retries and gradually increases the delay time for each subsequent attempt, reducing the load on system resources and the server . This approach mitigates network congestion and ensures efficient resource allocation by preventing immediate retry cycles for tasks. By providing a structured and automated way to handle transient errors, exponential backoff significantly improves the success rate of critical background tasks, such as data synchronization or fetching updates, which are essential for maintaining app reliability and user experience .

WorkManager is suited for deferrable and guaranteed asynchronous tasks that must be completed even if the app exits or the device restarts. It allows the scheduling of these tasks with constraints such as network conditions, charging state, or device storage . A significant advantage is its support for background execution through reliable scheduling that respects battery and memory resources, useful for operations like downloading files or performing network synchronization tasks. With built-in retry mechanisms and the ability to schedule work to repeat, it handles network failures gracefully by offering exponential backoff strategies for retries, ensuring tasks eventually complete successfully under unstable network conditions .

You might also like