Przejdź do treści
Biblioteka skilli
Programowanie · Nauka i wyjaśnianie

android

/android

Odpowiada na pytania o programowanie na Androida: Kotlin, Jetpack Compose, architektura, MVVM, Clean Architecture, Room, Hilt, Retrofit i testowanie.

Repozytorium
agent-skills ↗
Licencja
MIT
Ostatnia zmiana repozytorium
10.10.2026

Ocena i bezpieczeństwo

100/ 100Klasa: dobry
Format25 / 25
Frontmatter z nazwą i opisem, poprawna nazwa, opis do 1024 znaków, nazwa zgodna z folderem.
Odkrywalność25 / 25
Opis mówi, kiedy użyć skilla, ma sensowną długość i jest w 3. osobie.
Treść35 / 35
Co najmniej 150 słów i do 500 linii, nagłówki, listy kroków, przykłady albo kod.
Higiena15 / 15
Bez zaślepek typu TODO, bez ścieżek Windows, z licencją.
Ryzykobrak sygnałów w skanie
Pliki w paczce
8
Skrypty
0
Komentarze HTML
0
Adresy URL w SKILL.md
1
Przestarzałość

Brak sygnałów. Repozytorium zmienione 10.10.2026, bez odwołań do wycofanych modeli i API.

Licencja

MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.

Co robi i kiedy

Odpowiada na pytania o programowanie na Androida: Kotlin, Jetpack Compose, architektura, MVVM, Clean Architecture, Room, Hilt, Retrofit i testowanie.

Oryginalny opis (EN)

Use this skill when the user asks about Android development, Kotlin, Jetpack Compose, Android architecture, MVVM, Clean Architecture, Room, Hilt, Retrofit, or Android testing.

Jak działa

  1. Purpose
  2. Agent Protocol
  3. Workflow
  4. Architecture Decision Trees
  5. Project Structure
  6. MVVM + Clean Architecture
  7. Jetpack Compose UI
  8. Room Database
  9. Hilt DI
  10. Testing
Sekcje z nagłówków SKILL.md, w oryginale · 494 linii, 1 906 słów
Podgląd SKILL.md
---
name: android
description: >
  Use this skill when the user asks about Android development, Kotlin, Jetpack
  Compose, Android architecture, MVVM, Clean Architecture, Room, Hilt, Retrofit,
  or Android testing.
version: "2.0.0"
author: "j4flmao"
license: "MIT"
compatibility:
  claude-code: true
  cursor: true
  codex: true
  windsurf: true
tags: [mobile, android, phase-4]
---

# Android Native

## Purpose
Implement Android native applications using Kotlin, Jetpack Compose, MVVM+Clean Architecture, Coroutines+Flow, Hilt DI, Room, and comprehensive testing.

## Agent Protocol

### Trigger
User request includes: `android`, `kotlin`, `jetpack`, `compose`, `android architecture`, `android testing`, `room`, `hilt`.

### Input Context
- Android SDK version (compileSdk / minSdk / targetSdk)
- Kotlin version
- Build system (Gradle KTS)
- Architecture pattern (MVVM, Clean, MVI)

### Output Artifact
A markdown document containing:
- Project structure
- Jetpack Compose setup
- MVVM+Clean Architecture
- Coroutines+Flow concurrency
- Hilt dependency injection
- Room database setup
- JUnit + Espresso test plan

### Response Format
Produce the artifact directly. No preamble, no postamble, no explanations. No filler, no hedging, no transitions. Strip articles a/an/the where unambiguous. Compress output — why use many token when few do trick.

### Max Response Length
4096 tokens

## Workflow

### Step 1: Set Up Project Structure
Organize code with Clean Architecture layers: data, domain, ui, and di with feature-based packaging.

### Step 2: Implement Domain Layer
Define domain models, repository interfaces, and use cases independent of framework dependencies.

### Step 3: Implement Data Layer
Set up Room database with DAOs and entities, Retrofit API service, and repository implementations bridging local and remote sources.

### Step 4: Configure Dependency Injection
Set up Hilt modules for database, network, and repository bindings with appropriate scopes.

### Step 5: Build UI with Jetpack Compose
Create ViewModels with StateFlow, Compose screens with state collection, and handle loading/error/success states.

### Step 6: Write Tests
Cover domain use cases with JUnit + MockK unit tests and UI screens with Compose + Espresso UI tests.

## Architecture Decision Trees

### Architecture Selection
```
App complexity?
├── Simple CRUD (<10 screens, no complex state)
│   → MVVM + Repository — ViewModel → Repository → API/DB
│   → No UseCase layer needed
├── Complex state (real-time, multi-step forms)
│   → MVI with sealed Intent/State classes, reducer pattern
│   → Single state object per screen
└── Large codebase (5+ teams, shared domain)
    → Clean Architecture with strict layer separation
    → Domain module shared across features
```

### DI Strategy
```
Team preference?
├── Annotation-based → Hilt
│   Pros: compile-time verification, @HiltViewModel, less boilerplate
│   Cons: slower build, kapt/ksp overhead
├── Manual DI → Koin
│   Pros: no annotation processing, fast builds, easy to learn
│   Cons: runtime errors for missing bindings
└── Compiler-assisted → Dagger (raw)
    Pros: most control, mature
    Cons: steep learning curve, verbose
```

### Navigation Approach
```
Single-activity?
├── Yes → Jetpack Navigation Compose
│   NavHost with sealed Route class, type-safe arguments
├── Multi-activity → Navigation component with XML
└── Feature-modules → Dynamic feature navigation with NavDeepLink
```

### Image Loading Strategy
```
Network images needed?
├── Yes, Coil — Kotlin coroutines, Compose integration, memory-efficient
└── Yes, Glide — Mature, animated GIF/WebP, disk cache, OK
    Coil preferred for new projects — lighter (150KB vs ~500KB)
```

### Background Work Strategy
```
WorkManager vs Foreground Service vs AlarmManager
├── Deferrable, reliable → WorkManager (constraints, chaining, battery-optimized)
├── User-visible must continue → Foreground Service (notification required)
└── Exact timing needed → AlarmManager (limited, consider ScheduleTaskExecutor)
```

## Project Structure

```
app/
├── src/main/java/com/example/app/
│   ├── App.kt
│   ├── MainActivity.kt
│   ├── data/
│   │   ├── local/
│   │   │   ├── AppDatabase.kt
│   │   │   ├── OrderDao.kt
│   │   │   └── OrderEntity.kt
│   │   ├── remote/
│   │   │   ├── ApiService.kt
│   │   │   └── OrderResponse.kt
│   │   └── repository/
│   │       └── OrderRepositoryImpl.kt
│   ├── di/
│   │   ├── AppModule.kt
│   │   ├── DatabaseModule.kt
│   │   └── NetworkModule.kt
│   ├── domain/
│   │   ├── model/
│   │   │   └── Order.kt
│   │   ├── repository/
│   │   │   └── OrderRepository.kt
│   │   └── usecase/
│   │       └── GetOrdersUseCase.kt
│   └── ui/
│       ├── orders/
│       │   ├── OrderListScreen.kt
│       │   ├── OrderDetailScreen.kt
│       │   └── OrderViewModel.kt
│       └── theme/
└── src/test/
    └── ...
```

## MVVM + Clean Architecture

```kotlin
// domain/model/Order.kt
data class Order(
    val id: String,
    val customerName: String,
    val total: Double,
    val status: OrderStatus
)

enum class OrderStatus { PENDING, SHIPPED, DELIVERED }

// domain/repository/OrderRepository.kt
interface OrderRepository {
    suspend fun getOrders(): Result<List<Order>>
    suspend fun getOrder(id: String): Result<Order>
}

// domain/usecase/GetOrdersUseCase.kt
class GetOrdersUseCase(private val repo: OrderRepository) {
    suspend operator fun invoke(): Result<List<Order>> = repo.getOrders()
}
```

## Jetpack Compose UI

```kotlin
// ui/orders/OrderViewModel.kt
@HiltViewModel
class OrderViewModel @Inject constructor(
    private val getOrders: GetOrdersUseCase
) : ViewModel() {
    private val _state = MutableStateFlow<OrderUiState>(OrderUiState.Loading)
    val state: StateFlow<OrderUiState> = _state.asStateFlow()

    fun loadOrders() {
        viewModelScope.launch {
            _state.value = OrderUiState.Loading
            getOrders()
                .onSuccess { _state.value = OrderUiState.Success(it) }
                .onFailure { _state.value = OrderUiState.Error(it.message) }
        }
    }
}

sealed interface OrderUiState {
    data object Loading : OrderUiState
    data class Success(val orders: List<Order>) : OrderUiState
    data class Error(val message: String?) : OrderUiState
}

// ui/orders/OrderListScreen.kt
@Composable
fun OrderListScreen(
    viewModel: OrderViewModel = hiltViewModel(),
    onOrderClick: (String) -> Unit
) {
    val state by viewModel.state.collectAsStateWithLifecycle()

    LaunchedEffect(Unit) { viewModel.loadOrders() }

    when (val s = state) {
        is OrderUiState.Loading -> CircularProgressIndicator()
        is OrderUiState.Error -> ErrorMessage(s.message, onRetry = viewModel::loadOrders)
        is OrderUiState.Success -> LazyColumn {
            items(s.orders, key = { it.id }) { order ->
                OrderCard(order = order, onClick = { onOrderClick(order.id) })
            }
        }
    }
}

@Composable
fun OrderCard(order: Order, onClick: () -> Unit) {
    Card(modifier = Modifier.clickable(onClick = onClick)) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(text = order.customerName, style = MaterialTheme.typography.titleMedium)
            Text(text = "$${order.total}", style = MaterialTheme.typography.bodyLarge)
        }
    }
}
```

## Room Database

```kotlin
// data/local/OrderEntity.kt
@Entity(tableName = "orders")
data class OrderEntity(
    @PrimaryKey val id: String,
    @ColumnInfo(name = "customer_name") val customerName: String,
    val total: Double,
    val status: String
)

// data/local/OrderDao.kt
@Dao
interface OrderDao {
    @Query("SELECT * FROM orders")
    fun getAll(): Flow<List<OrderEntity>>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertAll(orders: List<OrderEntity>)

    @Query("DELETE FROM orders WHERE id = :id")
    suspend fun deleteById(id: String)
}

// data/local/AppDatabase.kt
@Database(entities = [OrderEntity::class], version = 1, exportSchema = true)
abstract class AppDatabase : RoomDatabase() {
    abstract fun orderDao(): OrderDao
}
```

## Hilt DI

```kotlin
// di/AppModule.kt
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Provides @Singleton
    fun provideOrderRepository(
        api: ApiService,
        dao: OrderDao
    ): OrderRepository = OrderRepositoryImpl(api, dao)
}

// di/NetworkModule.kt
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides @Singleton
    fun provideApiService(): ApiService {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .addConverterFactory(MoshiConverterFactory.create())
            .addCallAdapterFactory(CoroutineCallAdapterFactory())
            .client(OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .addInterceptor(HttpLoggingInterceptor().apply {
                    level = if (BuildConfig.DEBUG) BODY else NONE
                })
                .build())
            .build()
            .create(ApiService::class.java)
    }
}

// di/DatabaseModule.kt
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
    @Provides @Singleton
    fun provideDatabase(@ApplicationContext ctx: Context): AppDatabase {
        return Room.databaseBuilder(ctx, AppDatabase::class.java, "app-db")
            .fallbackToDestructiveMigration()
            .build()
    }

    @Provides fun provideOrderDao(db: AppDatabase): OrderDao = db.orderDao()
}
```

## Testing

### Unit Test (JUnit + MockK)

```kotlin
class GetOrdersUseCaseTest {
    private val repo = mockk<OrderRepository>()
    private val useCase = GetOrdersUseCase(repo)

    @Test
    fun `returns orders successfully`() = runTest {
        val orders = listOf(Order("1", "Test", 100.0, OrderStatus.PENDING))
        coEvery { repo.getOrders() } returns Result.success(orders)

        val result = useCase()

        assertTrue(result.isSuccess)
        assertEquals(orders, result.getOrThrow())
    }

    @Test
    fun `returns failure when repository fails`() = runTest {
        coEvery { repo.getOrders() } returns Result.failure(IOException("Network error"))

        val result = useCase()

        assertTrue(result.isFailure)
        assertTrue(result.exceptionOrNull() is IOException)
    }
}
```

### UI Test (Compose + Espresso)

```kotlin
@RunWith(AndroidJUnit4::class)
class OrderListScreenTest {
    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun displaysOrders() {
        val viewModel = mockk<OrderViewModel>()
        every { viewModel.state } returns MutableStateFlow(
            OrderUiState.Success(listOf(
                Order("1", "Alice", 50.0, OrderStatus.PENDING)
            ))
        ).asStateFlow()

        composeTestRule.setContent {
            OrderListScreen(viewModel = viewModel, onOrderClick = {})
        }

        composeTestRule.onNodeWithText("Alice").assertIsDisplayed()
    }

    @Test
    fun showsErrorState() {
        val viewModel = mockk<OrderViewModel>()
        every { viewModel.state } returns MutableStateFlow(
            OrderUiState.Error("Failed to load")
        ).asStateFlow()

        composeTestRule.setContent {
            OrderListScreen(viewModel = viewModel, onOrderClick = {})
        }

        composeTestRule.onNodeWithText("Failed to load").assertIsDisplayed()
    }
}
```

## Compose Performance Patterns

```kotlin
// Stable data classes — Compose skips recomposition when inputs are stable
@Stable
data class OrderUiModel(val id: String, val name: String, val total: Double)

// derivedStateOf for expensive computations
val totalPrice by remember(orders) {
    derivedStateOf { orders.sumOf { it.total } }
}

// LazyColumn keys for stable identity
items(orders, key = { it.id }) { order -> OrderCard(order) }

// Remember lambda to avoid allocation on recomposition
val onItemClick = remember { { id: String -> onOrderClick(id) } }

// ContentType for list-item differentiation
items(orders, key = { it.id }, contentType = { "order" }) { ... }
```

## Compose Modifier Best Practices

- Modifier order matters: `size` → `padding` → `background` → `clickable` (outer to inner)
- Klibs `Modifier.composed` for reusable modifier chains
- Avoid `Modifier.absoluteOffset` — prefer `Modifier.offset` for RTL support
- `Modifier.clipToBounds()` to prevent content overflow
- `Modifier.alpha(0f)` vs `Modifier.visible(false)` — invisible keeps layout space, gone releases it

## Production Considerations

- ProGuard/R8 rules: keep `@Keep` annotations, Moshi adapters, Retrofit interfaces
- Network security config for certificate pinning
- Baseline Profiles for startup optimization (30%+ faster cold start)
- LeakCanary for memory leak detection in debug builds
- Chucker for network inspection in debug builds
- StrictMode for detecting disk/network on main thread during development
- App Startup library for ordered, lazy SDK initialization

## Kotlin Coroutines & Flow Best Practices

- `viewModelScope.launch` for fire-and-forget operations (logging, analytics)
- `viewModelScope.async` for concurrent decomposition (parallel API calls)
- `flatMapLatest` for search-as-you-type debounced queries
- `stateIn(WhileSubscribed(5000))` to keep upstream active for 5s after last subscriber
- `catch { emit(UiState.Error(it)) }` for error recovery in Flow chains
- `Retrofit suspend functions` are main-safe — no need to wrap with `withContext(IO)`
- Room DAO `Flow` automatically runs on background thread
- `Dispatchers.IO` for blocking operations, `Dispatchers.Default` for CPU-heavy work

## Package Structure Options

```
Feature-first (recommended for medium+ apps):
com.example.app/
├── feature/orders/
│   ├── data/ local/ remote/ repository/
│   ├── domain/ model/ repository/ usecase/
│   └── ui/ OrderListScreen OrderViewModel
├── core/ network/ database/ di/ testing/

Layer-first (simple apps):
com.example.app/
├── data/
├── domain/
├── ui/
└── di/
```

## Anti-Patterns

- **God ViewModels**: ViewModel handling logic for multiple screens — split per screen
- **Repository exposing raw data sources**: Never return `ApiResult` or `DbModel` — map to domain models
- **Hilt unscoped bindings**: Always declare scope — unscoped = new instance every injection
- **CollectAsState instead of collectAsStateWithLifecycle**: Without lifecycle awareness, collection leaks when screen is in background
- **MutableStateFlow exposure**: Expose as `StateFlow`, keep `MutableStateFlow` private
- **Using GlobalScope**: Never use `GlobalScope.launch` — creates leaked coroutines tied to app process
- **Main thread DB access**: Room on main thread throws — use `suspend` functions or `Flow`
- **Ignoring configuration changes**: State in ViewModel survives rotation; state in `remember` does not
- **Deep layout hierarchy**: Compose recomposes deeply nested layouts inefficiently — keep composable depth <10 levels

## Rules

- Repository interfaces belong in domain layer; implementations in data layer
- ViewModels expose state via StateFlow, never expose mutable state
- Hilt modules must declare explicit scopes — no unscoped bindings for singletons
- Room operations on IO thread — use coroutine dispatchers or Room's built-in threading
- Compose screens collect StateFlow with collectAsStateWithLifecycle, not collectAsState
- Use sealed interfaces for UI state to represent loading, success, and error
- DI modules are in a separate package — never scatter provides across feature packages
- Baseline Profiles for all release builds targeting startup performance
- Compose Modifier order: size → padding → background → clickable (outside-in)
- Navigation routes defined in a single sealed class — never stringly-typed routes
- Image loading via Coil in Compose with `AsyncImage` or `rememberAsyncImagePainter`
- ProGuard rules must keep all Moshi/Retrofit/Kotlin serialization classes

## References
  - references/android-advanced.md — Android Advanced Topics
  - references/android-architecture.md — Android Architecture — MVVM + Clean Architecture
  - references/android-fundamentals.md — Android Fundamentals
  - references/compose-performance.md — Jetpack Compose Performance Optimization
  - references/hilt-di.md — Hilt Dependency Injection
  - references/jetpack-compose.md — Jetpack Compose
  - references/testing.md — Android Testing
## Handoff

Hand off to `mobile/universal/deployment/SKILL.md` for deployment.
Pliki w paczce (8)
  • SKILL.md 17 KB
  • references/android-advanced.md 6 KB
  • references/android-architecture.md 14 KB
  • references/android-fundamentals.md 5 KB
  • references/compose-performance.md 10 KB
  • references/hilt-di.md 1 KB
  • references/jetpack-compose.md 1 KB
  • references/testing.md 2 KB

Wersje

RepozytoriumWynikLicencja
Ta strona · j4flmao/agent-skills100MIT
lynricsy/hyperskills100MIT
clawic/skills90MIT
intentic/intentic86MIT

Migawka bazy z 13.11.2026 · wersja paczki 6312c97e85ec (skrót SHA-256 całej paczki)

Pobrania w ostatnich 30 dniach: 0 · ranking

Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.

Podobne skille

  • 100android-development
    Tworzy produkcyjne aplikacje Android według wytycznych Google, z Kotlinem, Compose, MVVM, Hilt, Room i modułami projektu.
  • 100kotlin-android
    Pomaga budować i naprawiać natywne aplikacje Android w Kotlinie i Jetpack Compose w warstwowej architekturze UDF: ViewModel, StateFlow, Hilt, Room, Retrofit, coroutines i Navigation.
  • 100android-kotlin
    Wspiera tworzenie aplikacji na Androida w Kotlinie: Jetpack Compose, korutyny i Flow, architektura MVVM oraz nowoczesne praktyki.
  • 95android-architecture
    Pomaga wdrażać MVVM, czystą architekturę i wstrzykiwanie zależności z Hilt oraz układać warstwy aplikacji Android.
  • 100android-dev
    Stanowi bazę dla całej pracy nad Androidem i Kotlin Multiplatform: Gradle, Hilt, Room, Retrofit, Ktor, ViewModel, Compose, wzorce MVVM i MVI oraz API Jetpack i AndroidX.
  • 100claude-android-ninja
    Buduje i migruje aplikacje Android w Kotlinie z Jetpack Compose, MVVM, Hilt, Room 3, Navigation3 i wielomodułowym Gradle, w tym synchronizację offline-first i migrację targetSdk.

Uwagi i zgłoszenia

Wiadomość trafi do Bartosza Sokolińskiego. Adres e-mail jest potrzebny tylko do odpowiedzi. Szczegóły w polityce prywatności.