JetBrains logo

Skill

android

build Android applications with Kotlin

Covers Kotlin Android Mobile Engineering

Description

Senior Android engineer workflows — Kotlin-first (Java legacy supported), Jetpack Compose + View system, MVVM, Coroutines/Flow, Room, Retrofit, Hilt, plus device orchestration via plugin tools (device management, logcat, crash reports, app run) and mobile-mcp for UI interaction (element tree, taps, swipes). Use when implementing features, debugging crashes, fixing builds, writing tests, reviewing Android code, or running QA on an emulator.

SKILL.md

Android

Senior Android developer workflows. Covers both the codebase layer (Kotlin / Compose / MVVM / Coroutines / Room / Retrofit) and the device layer (plugin tools for device management and diagnostics, mobile-mcp for UI interaction).

Self-contained. This skill does not require kotlin-engineer. All Kotlin/coroutine rules relevant for Android are included here.

Reference Guide

TopicReferenceLoad When
Implement a featurereferences/implement.mdAdding new screen / feature / data layer
Jetpack Compose patternsreferences/compose.mdCompose UI, state, navigation, animation, Hilt, side effects
View system / XML UIreferences/view-system.mdXML layouts, ViewBinding, RecyclerView, Fragments (legacy / mixed projects)
Debug a crashreferences/debug.mdCrash, unexpected behavior, stacktrace in logcat
Fix a buildreferences/build-fix.mdGradle error, compile error, KSP/KAPT failure, resource error
Write & run testsreferences/test.mdUnit tests (VM/UseCase) or Compose/Espresso UI tests
Code reviewreferences/review.mdReviewing diff for leaks, threading, lifecycle, perf
Manual QA on emulatorreferences/qa.mdRunning scenarios on device, visual verification
Device setup / emulator bootstrapreferences/device-setup.mdNo device available, need to bring up an emulator
Mobile MCP usagereferences/mobile-mcp.mdReading UI element tree, taps, swipes, text input via mobile-mcp
ADB fallbackreferences/adb.mdPlugin tool / mobile-mcp not available — use raw ADB shell as a last resort
Accessibilityreferences/accessibility.mdAdding or reviewing UI — labels, touch targets, semantics, headings

Google Official Skills

For specific migration or upgrade tasks, install the relevant Google Android skill into the project:

# See all available skills and their descriptions
npx android-skills-pack list

# Install only if the skill is not already installed
npx android-skills-pack install --target junie --skill <name>

Relevant hints are in each reference file. When a task matches a Google skill, install it only if not already present.

Tool priority (three-tier fallback chain)

Use the first available layer for any device/app operation:

  1. Plugin tools — first choice. Device management (list/start/stop emulator, list AVDs), app lifecycle (build/install/launch/clear), diagnostics (logcat, last crash, ANR traces), system tweaks (permissions, network, dark mode), Compose preview rendering. Fastest, structured output, no shell parsing needed.
  2. mobile-mcp — UI interaction only. Reading the UI element tree, taps, swipes, text input, back/home, orientation, opening URLs, screenshot fallback. Use it when the action involves interacting with the UI surface.
  3. ADB shell — last-resort fallback. Only when neither a plugin tool nor mobile-mcp covers the operation, or when one of them is unavailable. See references/adb.md.

The core loop

Whenever the agent touches the device, it follows this loop — no blind actions:

read UI element tree (mobile-mcp)        → observe current state (text, ids, bounds)
     ↓
action (mobile-mcp: tap / swipe / type / press button)
     ↓
read UI element tree (mobile-mcp)        → verify UI changed as expected
     ↓
read logcat (plugin tool)                → catch silent crashes

The element tree is the primary observation channel — it returns structured data (text, resource-id, bounds) that the agent can read directly without vision. A screenshot is a fallback only: use it when elements are missing from the tree (custom-drawn views, games, WebView content, visual layout issues).

Before running on device — verify Compose UI via headless preview

For any UI-touching task (Compose), render @Preview composables before running on the emulator:

  • display_android_compose_preview(path) — when the file path is known (typical case after editing a file).
  • read_android_last_preview (no args) — when the file is already open in the editor and the path is not known.

Both return one image per @Preview and trigger a build if needed. Only proceed to the emulator after the preview looks right.

Key Patterns

MVVM + UDF (Compose)

// State — what's on screen right now
sealed interface UserUiState {
    data object Loading : UserUiState
    data class Success(val user: User) : UserUiState
    data class Error(val message: String) : UserUiState
}

// ViewModel — no Context, no View, no Activity
class UserViewModel(
    private val repo: UserRepository,
) : ViewModel() {
    private val _state = MutableStateFlow<UserUiState>(UserUiState.Loading)
    val state: StateFlow<UserUiState> = _state.asStateFlow()

    fun load(id: String) = viewModelScope.launch {
        _state.value = UserUiState.Loading
        _state.value = runCatching { repo.user(id) }
            .onFailure { if (it is CancellationException) throw it }  // never swallow cancellation
            .fold({ UserUiState.Success(it) }, { UserUiState.Error(it.message ?: "Error") })
    }
}

// Composable — observes state with lifecycle awareness
@Composable
fun UserScreen(vm: UserViewModel = hiltViewModel()) {
    val state by vm.state.collectAsStateWithLifecycle()
    when (val s = state) {
        UserUiState.Loading     -> LoadingIndicator()
        is UserUiState.Error    -> ErrorView(s.message) { vm.load("me") }
        is UserUiState.Success  -> UserContent(s.user)
    }
}

Full Repository / Retrofit / Fragment examples → references/implement.md.

Output Format

When implementing a feature:

  1. Plan — one sentence stating what changes and which layers are touched (UI / ViewModel / Repository / data).
  2. Code — implement bottom-up: data layer → domain → ViewModel → UI. Follow existing architecture patterns.
  3. Checklist — confirm: no Context in ViewModel, flows collected with collectAsStateWithLifecycle, runBlocking not used on main thread, no hardcoded colors/dp.

When reviewing code: call out MUST-DO / MUST-NOT violations, lifecycle leaks, threading issues, and N+1 data fetches. Suggest minimal fixes.

When running QA: follow the core loop — observe → act → verify. Delegate long scenarios to android-qa-agent.

Constraints

MUST DO:

  • Use Kotlin, Jetpack Compose, MVVM, Coroutines/Flow.
  • Prefer plugin tools for device management, app lifecycle, diagnostics (logcat, crashes, ANR), permissions, and system settings — they are the first-tier choice.
  • Use mobile-mcp for UI interaction: element tree, taps, swipes, text input, back/home, orientation, open-url.
  • Fall back to raw ADB shell only when neither tier covers the operation (references/adb.md).
  • Wrap every UI action: read element tree → act → read element tree, then check logcat.
  • When unit-testing, mock at the ApiService / Dao boundary so the Repository logic (cache-first, API fallback, error mapping) is actually exercised. See references/test.md.
  • Reuse existing architecture patterns; read 2–3 similar features before adding a new one.

MUST NOT DO:

  • Write new files in Java (Kotlin for all new code; keep existing Java files in Java).
  • Hold Context, View, Activity references in a ViewModel.
  • Call runBlocking on the main thread.
  • Swallow exceptions with empty catch blocks.
  • Hardcode dp/sp/colors — use MaterialTheme / theme tokens.
  • Bypass failing tests with @Ignore, skip flags, or weakened assertions.

Dedicated agent

For autonomous QA loops, delegate to the android-qa-agent — it runs scenarios on the emulator and produces a structured PASS/FAIL/BLOCKED report without modifying source code.

© 2026 YourAI.tools. Every skill from an identity-verified publisher.

Independent catalog. Not affiliated with, endorsed by, or sponsored by Anthropic or any listed publisher. All trademarks belong to their respective owners.