Lesson 70 of 83 advanced

Full Android Technical Mock Pack

Complete technical mock interview round with model answers and self-scoring rubric

Open interactive version (quiz + challenge)

Real-world analogy

A flight simulator does not teach you to fly by showing you videos — it puts you in the cockpit and makes you respond to real scenarios. This mock pack is your flight simulator: real questions, real pressure, and a rubric that tells you exactly where you need more practice.

What is it?

A full technical mock interview pack for senior Android engineers, covering Kotlin, Coroutines/Flow, Android components, Jetpack Compose, and architecture. Each question includes a model answer with a 1–4 self-scoring rubric. This pack simulates a real technical panel round and gives structured feedback so you know exactly what to study before the real interview.

Real-world relevance

Senior Android interviews at companies like Wise, Klarna, Spotify, N26, and Grab typically include 2–3 technical rounds: (1) a Kotlin/language fundamentals screen, (2) a systems/architecture deep-dive, and (3) a practical coding or review session. This mock pack covers the content of rounds 1 and 2. Candidates who complete 3 full mock rounds before interviewing report significantly higher confidence and offer rates.

Key points

Code example

// MOCK ROUND — ANSWER THESE WITHOUT LOOKING AT MODEL ANSWERS

// ============================================================
// SECTION 1: KOTLIN FUNDAMENTALS (Score each /4)
// ============================================================

// Q1: What is structured concurrency and why does it matter?
// [ANSWER SPACE — write or say your answer before reading below]

// MODEL ANSWER (Score /4):
// Structured concurrency means coroutines are scoped to their parent.
// When a parent scope is cancelled, all child coroutines are cancelled.
// When all children complete, the parent scope completes.
// This prevents coroutine leaks — unlike Thread or GlobalScope which
// have no automatic cleanup on lifecycle events.
// Real world: ViewModelScope cancels all launched coroutines when the
// ViewModel is cleared, preventing updates to destroyed UI.
// Gotcha: GlobalScope breaks structured concurrency — avoid it except
// for truly app-lifetime operations.

// ------------------------------------------------------------
// Q2: Explain StateFlow vs SharedFlow. When do you use each?
// [ANSWER SPACE]

// MODEL ANSWER:
// StateFlow: always has a current value (initial value required),
// replays the latest value to new collectors, conflates rapid updates.
// Use for: UI state (uiState: StateFlow<UiState>).
// SharedFlow: no initial value, configurable replay cache (0 to N),
// configurable buffer overflow strategy.
// Use for: one-shot events (navigation, snackbars) where you do not
// want new collectors to receive old events.
// Gotcha: StateFlow.value access is not safe across threads in general —
// always collect from a coroutine, not from a callback.

// ------------------------------------------------------------
// Q3: What triggers recomposition in Jetpack Compose?
// [ANSWER SPACE]

// MODEL ANSWER:
// Recomposition triggers when state read inside a composable changes.
// Compose tracks state reads at the composable level using snapshot state.
// Key rules:
//   - Only composables that READ the changed state recompose
//   - Composables are skippable if all parameters are stable and unchanged
//   - Unstable classes (List, non-data classes) force recomposition even
//     when the content is the same
// Gotcha: Lambdas that capture mutable state or are not remembered cause
// unnecessary recompositions. Use remember { derivedStateOf { ... } }
// to only recompose when computed value changes.

// ============================================================
// SECTION 2: ANDROID ARCHITECTURE (Score each /4)
// ============================================================

// Q4: Explain Clean Architecture dependency direction.
// [ANSWER SPACE]

// MODEL ANSWER:
// Dependencies point INWARD only:
//   UI layer -> Domain layer <- Data layer
// Domain layer (use cases, entities) has NO Android dependencies.
// Data layer implements domain interfaces (repository pattern).
// UI layer depends on domain, never on data directly.
// Why: domain layer can be unit tested with pure JVM, no Android mocks.
// Real world: a UseCase that calls repository.getTransactions() is
// testable without a database or network by injecting a fake repository.
// Gotcha: putting Android Context or Room entities in the domain layer
// violates the dependency rule and makes domain untestable.

// ------------------------------------------------------------
// Q5: How do you handle offline-first data synchronization?
// [ANSWER SPACE]

// MODEL ANSWER:
// Pattern: Single Source of Truth (SSOT) — Room is the only source
// the UI reads from. Network data flows: API -> Room -> UI via Flow.
// Implementation:
//   1. Repository.getItems() returns Flow<List<Item>> from Room
//   2. A background sync (WorkManager) fetches from API and writes to Room
//   3. Room emits updates automatically, UI reacts
// Conflict resolution: last-write-wins or timestamp-based or server-wins.
// Edge case: deletions — use soft delete (isDeleted flag) + sync timestamp
// rather than hard deletes, to avoid sync conflicts.

// ============================================================
// SELF-SCORING:
// After answering all questions:
//   - Score 1-4 on each question
//   - Average by category
//   - Weakest category = top priority before real interview
// ============================================================

Line-by-line walkthrough

  1. 1. Mock discipline: no notes, no IDE, timed — simulate real interview pressure to build the muscle memory you need on interview day.
  2. 2. Rubric 1 = fundamentally wrong or blank: immediately review the concept in the relevant lesson before continuing.
  3. 3. Rubric 2 = partial: you understand the surface, not the depth — study the mechanism and the edge cases.
  4. 4. Rubric 3 = solid: one or two gaps — these are the gaps interviewers will probe. Practice specifically for the gap.
  5. 5. Rubric 4 = exceptional: correct, complete, production nuance, edge case awareness. This is the senior bar.
  6. 6. Kotlin section covers: structured concurrency, coroutine mechanics, StateFlow vs SharedFlow, sealed classes, inline/reified, data class semantics.
  7. 7. Architecture section covers: Clean Architecture dependency direction, offline-first SSOT pattern, repository design, use case boundaries.
  8. 8. Compose section covers: recomposition triggers, stability, remember vs rememberSaveable vs derivedStateOf, side effects, performance.
  9. 9. Model answer format: Definition + Mechanism + When to use + Real-world example + Edge case/gotcha — use this structure in real interviews.
  10. 10. Scoring workflow: answer all questions, score each, average by category, target weakest category for focused review.
  11. 11. Spaced repetition: repeat weak-category questions 48 hours later, not immediately — spacing creates durable memory.
  12. 12. 3 full mock rounds before a real senior interview is the recommended minimum for confident performance.

Spot the bug

// KOTLIN BUG — FIND AND FIX:

class UserRepository(private val api: UserApi) {

    suspend fun getUser(id: String): User {
        return GlobalScope.async {
            api.fetchUser(id)
        }.await()
    }

    fun observeUsers(): Flow<List<User>> {
        return flow {
            while (true) {
                emit(api.fetchAllUsers())
                delay(30_000)
            }
        }
    }
}
Need a hint?
There are two bugs. One involves coroutine scope and structured concurrency. One involves the Flow and its lifecycle/cancellation behavior. What happens if the calling scope is cancelled in each case?
Show answer
Bug 1 (GlobalScope breaks structured concurrency): GlobalScope.async creates a coroutine with no parent, so if the caller's scope is cancelled (e.g. ViewModel cleared), the api.fetchUser() call continues running. This leaks the coroutine and wastes resources. Fix: remove GlobalScope entirely — the function is already suspend, so the caller's scope controls the lifecycle: suspend fun getUser(id: String): User = api.fetchUser(id). Bug 2 (Infinite Flow with no cancellation check): The while(true) loop in flow will continue even if the collector is cancelled, because flow builders do not automatically check for cancellation between emissions. Fix: replace while(true) with while(currentCoroutineContext().isActive) — or use Flow.cancellable() extension — to ensure the loop exits when the collector scope is cancelled.

Explain like I'm 5

This is like a practice exam where you answer the questions first, then check the answer key, and then give yourself a grade. But instead of school grades, you use 1 to 4: 1 means you had no idea, 4 means you nailed it completely. The point is not to cheat by reading the answers first — the point is to practice the feeling of answering hard questions under pressure, so the real exam feels familiar.

Fun fact

Mock interviews are the single highest-ROI interview preparation activity. Research published in the Journal of Applied Psychology found that candidates who completed structured mock interviews performed 24% better in real interviews than those who only studied content. The act of speaking answers aloud under simulated pressure creates the neural pathways needed for confident real-interview performance.

Hands-on challenge

Run a full timed mock using this pack. Set a timer for each question: Kotlin questions 5 minutes each, Architecture questions 10 minutes each. Write or speak your answer BEFORE reading the model answer. Score yourself honestly (1–4). Calculate your average by category. Identify your two weakest areas and revisit those lessons in this course. Repeat the mock on those categories 48 hours later and compare scores. Target: average 3.0+ across all categories before your real interview.

More resources

Open interactive version (quiz + challenge) ← Back to course: Android Interview Mastery