Skillquality 0.45

datastore

27 Android skills for AI agents (Claude Code, Codex, Cursor). Fixes Supabase auth, Hilt errors, design inconsistency, kapt→ksp, missing UiState states. Reduced my token bills 5×. FitGenZ AI shipped in 18 days.

Price
free
Protocol
skill
Verified
no

What it does

DataStore

DataStore is the modern replacement for SharedPreferences. Coroutine-based, type-safe, safe for Main thread.

Preferences DataStore — for simple key-value pairs

// Setup
implementation(libs.androidx.datastore.preferences)
// ✅ Define all preference keys in one place
object PreferenceKeys {
    val IS_DARK_THEME = booleanPreferencesKey("is_dark_theme")
    val ONBOARDING_COMPLETE = booleanPreferencesKey("onboarding_complete")
    val USER_ID = stringPreferencesKey("user_id")
    val NOTIFICATION_ENABLED = booleanPreferencesKey("notifications_enabled")
    val LANGUAGE = stringPreferencesKey("language")
    val FONT_SIZE = intPreferencesKey("font_size")
}

// ✅ Hilt module — create DataStore singleton
@Module
@InstallIn(SingletonComponent::class)
object DataStoreModule {
    @Provides
    @Singleton
    fun provideDataStore(@ApplicationContext context: Context): DataStore<Preferences> =
        PreferenceDataStoreFactory.create(
            corruptionHandler = ReplaceFileCorruptionHandler { emptyPreferences() },
            migrations = listOf(SharedPreferencesMigration(context, "legacy_prefs")),
            scope = CoroutineScope(Dispatchers.IO + SupervisorJob()),
            produceFile = { context.preferencesDataStoreFile("app_preferences") }
        )
}

// ✅ Repository pattern for DataStore
class UserPreferencesRepository @Inject constructor(
    private val dataStore: DataStore<Preferences>
) {
    // Read — returns Flow, auto-updates on change
    val isDarkTheme: Flow<Boolean> = dataStore.data
        .catch { exception ->
            if (exception is IOException) emit(emptyPreferences())
            else throw exception
        }
        .map { preferences -> preferences[PreferenceKeys.IS_DARK_THEME] ?: false }

    val onboardingComplete: Flow<Boolean> = dataStore.data
        .catch { if (it is IOException) emit(emptyPreferences()) else throw it }
        .map { it[PreferenceKeys.ONBOARDING_COMPLETE] ?: false }

    // Read all preferences at once
    val userPreferences: Flow<UserPreferences> = dataStore.data
        .catch { if (it is IOException) emit(emptyPreferences()) else throw it }
        .map { preferences ->
            UserPreferences(
                isDarkTheme = preferences[PreferenceKeys.IS_DARK_THEME] ?: false,
                notificationsEnabled = preferences[PreferenceKeys.NOTIFICATION_ENABLED] ?: true,
                language = preferences[PreferenceKeys.LANGUAGE] ?: "en",
                fontSize = preferences[PreferenceKeys.FONT_SIZE] ?: 16
            )
        }

    // Write — always suspend, safe on any coroutine
    suspend fun setDarkTheme(enabled: Boolean) {
        dataStore.edit { preferences ->
            preferences[PreferenceKeys.IS_DARK_THEME] = enabled
        }
    }

    suspend fun setOnboardingComplete() {
        dataStore.edit { preferences ->
            preferences[PreferenceKeys.ONBOARDING_COMPLETE] = true
        }
    }

    suspend fun updateLanguage(language: String) {
        dataStore.edit { preferences ->
            preferences[PreferenceKeys.LANGUAGE] = language
        }
    }

    suspend fun clearAll() {
        dataStore.edit { it.clear() }
    }
}

data class UserPreferences(
    val isDarkTheme: Boolean = false,
    val notificationsEnabled: Boolean = true,
    val language: String = "en",
    val fontSize: Int = 16
)

Proto DataStore — for complex structured data

// Setup
implementation(libs.androidx.datastore)
implementation(libs.protobuf.kotlin.lite)
// src/main/proto/user_settings.proto
syntax = "proto3";
option java_package = "com.company.app";
option java_multiple_files = true;

message UserSettings {
  bool dark_mode = 1;
  string language = 2;
  NotificationSettings notifications = 3;
  repeated string recent_searches = 4;
}

message NotificationSettings {
  bool enabled = 1;
  bool marketing = 2;
  bool updates = 3;
}
// ✅ Serializer for Proto DataStore
object UserSettingsSerializer : Serializer<UserSettings> {
    override val defaultValue: UserSettings = UserSettings.getDefaultInstance()

    override suspend fun readFrom(input: InputStream): UserSettings = try {
        UserSettings.parseFrom(input)
    } catch (e: InvalidProtocolBufferException) {
        throw CorruptionException("Cannot read proto", e)
    }

    override suspend fun writeTo(t: UserSettings, output: OutputStream) {
        t.writeTo(output)
    }
}

// ✅ Proto DataStore module
@Module
@InstallIn(SingletonComponent::class)
object ProtoDataStoreModule {
    @Provides
    @Singleton
    fun provideUserSettingsDataStore(@ApplicationContext context: Context): DataStore<UserSettings> =
        DataStoreFactory.create(
            serializer = UserSettingsSerializer,
            produceFile = { context.dataStoreFile("user_settings.pb") }
        )
}

ViewModel — read DataStore in ViewModel

// ✅ Map DataStore Flow to UiState in ViewModel
@HiltViewModel
class SettingsViewModel @Inject constructor(
    private val prefsRepository: UserPreferencesRepository
) : ViewModel() {

    val uiState: StateFlow<SettingsUiState> = prefsRepository.userPreferences
        .map { prefs ->
            SettingsUiState.Success(
                isDarkTheme = prefs.isDarkTheme,
                notificationsEnabled = prefs.notificationsEnabled,
                language = prefs.language
            )
        }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5_000),
            initialValue = SettingsUiState.Loading
        )

    fun onDarkThemeToggled(enabled: Boolean) {
        viewModelScope.launch {
            prefsRepository.setDarkTheme(enabled)
        }
    }
}

Migration from SharedPreferences

// ✅ Migrate automatically on first DataStore read
PreferenceDataStoreFactory.create(
    migrations = listOf(
        SharedPreferencesMigration(
            context = context,
            sharedPreferencesName = "legacy_prefs",
            keysToMigrate = setOf("is_dark_theme", "user_id")  // migrate specific keys only
        )
    ),
    produceFile = { context.preferencesDataStoreFile("app_preferences") }
)

Common Mistakes

❌ Using SharedPreferences — always use DataStore in new code ❌ Reading DataStore with .first() on Main thread — observe as Flow in ViewModel ❌ Creating multiple DataStore instances for same file — always @Singleton ❌ No corruption handler — add ReplaceFileCorruptionHandler { emptyPreferences() } ❌ Storing large data in DataStore — use Room for lists/complex objects ❌ Calling dataStore.edit {} from Main thread — always from a coroutine

Capabilities

skillsource-piyushverma0skill-datastoretopic-agent-skillstopic-ai-agenttopic-androidtopic-antigravitytopic-claude-codetopic-codextopic-cursortopic-gemini-clitopic-hilttopic-jetpack-composetopic-kotlintopic-material3

Install

Installnpx skills add piyushverma0/android-agent-skills
Transportskills-sh
Protocolskill

Quality

0.45/ 1.00

deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 8 github stars · SKILL.md body (6,913 chars)

Provenance

Indexed fromgithub
Enriched2026-05-18 19:09:09Z · deterministic:skill-github:v1 · v1
First seen2026-05-18
Last seen2026-05-18

Agent access