Skip to content
Skills Library
Programming · Building & coding

android-data-layer

/android-data-layer

Use when implementing the data layer in Android or KMP — the Repository pattern's layered error-propagation model (repository as the error boundary, sealed DataError, Result placement with and without a domain layer) and Room in commonMain (@ConstructedBy, BundledSQLiteDriver, per-target KSP).

Licence
MIT
Last repository change
19.09.2026

Assessment and security

100/ 100Class: good
Format25 / 25
Frontmatter with name and description, valid name, description up to 1,024 characters, name matching the folder.
Discoverability25 / 25
Description explains when to use the skill, has a reasonable length and uses third person.
Content35 / 35
At least 150 words and at most 500 lines, headings, step lists, examples or code.
Hygiene15 / 15
No placeholders such as TODO, no Windows paths, with a licence.
Riskno signals detected in the scan
Files in this package
1
Scripts
0
HTML comments
0
URLs in SKILL.md
0
Deprecation

No signals detected. Repository changed on 19.09.2026, without references to retired models or APIs.

Licence

MIT, open: use and modify while retaining author attribution.

What it does and when to use it

Use when implementing the data layer in Android or KMP — the Repository pattern's layered error-propagation model (repository as the error boundary, sealed DataError, Result placement with and without a domain layer) and Room in commonMain (@ConstructedBy, BundledSQLiteDriver, per-target KSP).

Original author description

Use when implementing the data layer in Android or KMP — the Repository pattern's layered error-propagation model (repository as the error boundary, sealed DataError, Result placement with and without a domain layer) and Room in commonMain (@ConstructedBy, BundledSQLiteDriver, per-target KSP).

How it works

  1. Error propagation — the layered model
  2. Room in KMP (commonMain)
Original SKILL.md headings · 68 lines, 509 words
SKILL.md preview
---
name: android-data-layer
description: Use when implementing the data layer in Android or KMP — the Repository pattern's layered error-propagation model (repository as the error boundary, sealed DataError, Result placement with and without a domain layer) and Room in commonMain (@ConstructedBy, BundledSQLiteDriver, per-target KSP).
---

# Android Data Layer

The data layer coordinates data from multiple sources; its public API is repository interfaces, and its internals (DAOs, API services, DTOs) never leak upward. This skill is the canonical home for the **error-propagation model**, plus the KMP-Room setup. **Related:** `android-skills:android-retrofit` (Retrofit service/OkHttp/Hilt wiring), `android-skills:android-dev` (overall app architecture).

## Error propagation — the layered model

The goal: data-layer errors (`IOException` / `HttpException` / `SQLiteException`) must never reach the ViewModel. Map them to a domain error type at the repository boundary. If the project already has an error convention, match it; otherwise a sealed `DataError` hierarchy is a reasonable default:

```kotlin
sealed class DataError(message: String, cause: Throwable? = null) : Exception(message, cause) {
    class Network(cause: Throwable) : DataError("Network error", cause)
    class Server(val code: Int, message: String?) : DataError("Server error $code: $message")
    class Local(cause: Throwable) : DataError("Local storage error", cause)
}

// repository = error boundary: catch platform exceptions, return Result<T> (no domain layer) or throw DataError (with one)
suspend fun refreshNews(): Result<Unit> = withContext(io) {
    try { newsDao.insertAll(newsApi.fetchLatest().map(NewsDto::toEntity)); Result.success(Unit) }
    catch (e: IOException) { Result.failure(DataError.Network(e)) }
    catch (e: HttpException) { Result.failure(DataError.Server(e.code(), e.message())) }
}
```

The boundary moves outward by one layer when a domain layer exists:

1. **Data sources** throw platform/library exceptions (`IOException`, `HttpException`, `SQLiteException`).
2. **Repository** is the error boundary — catch those and remap to `DataError`; never let raw platform types leak. *Without a domain layer (simple MVVM):* the repository returns `Result<T>` directly and the ViewModel handles it without knowing about platform exceptions.
3. **Use cases** (when present) are the `Result` boundary — the repository instead *throws* `DataError`, and the use case catches it and returns `Result<T>` with a domain-specific error model. Use cases never catch platform exception types.
4. **ViewModels** handle `Result<T>` and map it to UI state (explicit loading / success / error).

(Default to the `Entity` suffix — `ArticleEntity` — for Room types; match an existing convention such as a `Cached` prefix if the project already uses one.)

## Room in KMP (`commonMain`)

Room has been KMP-stable since 2.7.0. The shared setup differs from the Android-only setup in three places:

1. **`@ConstructedBy(...)`** on the `@Database`, paired with an `expect object` Room generates per-platform `actual`s for.
2. **`BundledSQLiteDriver`** (from `androidx.sqlite:sqlite-bundled`) — pins the same SQLite version across Android/iOS/JVM/web (Android's system SQLite drifts between API levels and devices).
3. **`setQueryCoroutineContext(Dispatchers.IO)`** — Android Room defaults this; KMP doesn't.

```kotlin
// commonMain
@Database(entities = [ArticleEntity::class], version = 1, exportSchema = true)
@ConstructedBy(AppDatabaseConstructor::class)
abstract class AppDatabase : RoomDatabase() { abstract fun articleDao(): ArticleDao }

@Suppress("KotlinNoActualForExpect")
expect object AppDatabaseConstructor : RoomDatabaseConstructor<AppDatabase>

fun getRoomDatabase(builder: RoomDatabase.Builder<AppDatabase>): AppDatabase =
    builder.setDriver(BundledSQLiteDriver()).setQueryCoroutineContext(Dispatchers.IO).build()
```

Each platform provides its own builder — Android `Room.databaseBuilder(context, AppDatabase::class.java, "app.db")`; iOS/JVM `Room.databaseBuilder<AppDatabase>(databasePath = …)`. **KSP must be wired per target** (`ksp(libs.androidx.room.compiler)` is Android-only):

```kotlin
dependencies {
    add("kspAndroid", libs.androidx.room.compiler)
    add("kspIosArm64", libs.androidx.room.compiler)
    add("kspIosSimulatorArm64", libs.androidx.room.compiler)
    // … one per target
}
room { schemaDirectory("$projectDir/schemas") }   // export the schema for migration-history tracking
```

For pure-Android projects, skip `@ConstructedBy` and call `Room.databaseBuilder(context, AppDatabase::class.java, "app.db")` directly — Room behaves identically; the KMP setup is opt-in when the data layer must live in `commonMain`.

Versions

The database has no other skills named android-data-layer.

Database snapshot: 13.11.2026 · package version bd9f6239dfbb (SHA-256 digest of the entire package)

Downloads in the last 30 days: 0 · ranking

Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.

Similar skills

  • 100error-handling-result
    Typed error handling in Kotlin/KMP shared code - kotlin.Result and runCatching, modeling outcomes with sealed result types (sealed interface with Success/Failure), and Arrow's Either, the either {} builder, and the Raise DSL (raise, bind, ensure, recover, context(Raise<E>)). Use…
  • 95kmp-di
    Dependency injection for Kotlin Multiplatform (KMP/CMP) - shared Koin modules in commonMain, expect/actual platform modules, initKoin()/KoinApplication startup shared across Android and iOS, and consuming the Koin graph from Swift/iOS. Use for multiplatform or shared DI wiring.…
  • 100android-clean-architecture
    Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.
  • 100android-dev
    Use this skill as the baseline for ALL Android and Kotlin Multiplatform (KMP) work — whenever the user mentions Android, Kotlin (in an Android context), KMP, CMP, commonMain, androidMain, iosMain, AndroidManifest, Gradle, build.gradle, Hilt, Dagger, Room, Retrofit, Ktor,…
  • 90matrixscan-batch-kmp
    MatrixScan Batch (MatrixScan, BarcodeBatch, Scandit KMP) in Kotlin Multiplatform (KMP) projects (`com.scandit.datacapture.kmp` packages, `com.kmp.datacapture.*` imports) — tracking and scanning multiple barcodes at once in shared commonMain code with Android/iOS hosts and the…
  • 100kotlin-multiplatform
    Kotlin Multiplatform (KMP) is JetBrains' technology for sharing Kotlin code between Android, iOS, web, and desktop applications while keeping the UI native on each platform. Use when a user asks to set up a KMP shared module, share business logic, networking or a data layer…

Feedback and reports

Your message goes to Bartosz Sokoliński. An email address is needed only for a reply. See the privacy policy.