rcosteira79/android-skills

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,…

View source

How to use

  1. Copy the installation command and review the source package before installing it in your own agent environment.
  2. Check the source document for required tools, credentials and supported hosts.
  3. Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/rcosteira79/android-skills --skill android-data-layer

Before you start

  • Installation does not include a model subscription, API allowance or permission to access your files.
  • Repository stars and installation counts describe activity, not an independent quality or security test.
Original skill document

Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.

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 actuals 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.

Related by task

from this repository

More skills

All skills
rcosteira79
Community

android-debugging

Use when debugging Android or KMP issues — Android-specific techniques covering Logcat, ADB, ANR traces, R8 stack trace decoding, memory leaks, Gradle build failures, and Compose recomposition bugs, on a root-cause-first foundation.

installs
1
GitHub stars
155
Updated
Sep 19
rcosteira79
Community

android-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, ViewModel, LiveData, StateFlow, SharedFlow, Compose, Activity, Fragment, Intent, ADB, Logcat, MVVM, MVI, repository pattern, or any Android SDK / Jetpack / AndroidX API. Always load this skill alongside the more specific skills

installs
1
GitHub stars
155
Updated
Sep 19
rcosteira79
Community

android-ux

Use when designing or reviewing Android UI — applies Material Design 3 UX principles covering touch targets, spacing, navigation patterns, accessibility, animation timing, and platform conventions. Includes an M3 compliance audit that scores screens across 10 categories. Complements the compose skill with design-level decisions.

installs
1
GitHub stars
155
Updated
Sep 19
rcosteira79
Community

compose

Compose and Compose Multiplatform expert for UI development across Android, Desktop, iOS, and Web. Covers state management, composition, animations, navigation, performance, design-to-code workflows, and production crash patterns, backed by source analysis from androidx/androidx and JetBrains/compose-multiplatform-core. Use whenever the user mentions Compose, @Composable, remember, LaunchedEffect, Scaffold, NavHost, NavDisplay, MaterialTheme, LazyColumn, Modifier, recomposition, Compose Multipla

installs
1
GitHub stars
155
Updated
Sep 19