mcpField
D
datastore

datastore

github.com/rcosteira79開発165138 回インストール6 週間前に更新
リポジトリ

datastore について

AndroidおよびKotlin Multiplatform開発者向けのJetpack DataStoreスキルです。Preferences、型付きストレージ、Roomを比較し、エラー復旧とプラットフォーム別ファイルパスの注意点を示します。

主な機能

  1. 01Preferencesと型付きストレージの指針
  2. 02DataStoreとRoomの選択
  3. 03IOExceptionに限定したFlow処理
  4. 04型付きストアの破損復旧
  5. 05プラットフォーム別パスファクトリー

活用シーン

  1. 01設定や構造化データの保存先選択
  2. 02DataStore読み取りエラーの安全な処理
  3. 03破損した型付きストアファイルの復旧
  4. 04Android、iOS、JVMでのストア作成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/rcosteira79/android-skills --skill datastore

インストール後、Claude Code で/datastoreを入力して読み込まれたか確認します。

詳細

Android および KMP 向け Jetpack DataStore

リアクティブなコルーチンベースのキーと値/型付きストレージです。同じ androidx.datastore:datastore-preferences-core が Android、iOS、JVM で動作し、プラットフォーム固有なのはファイルパスの生成処理だけです。(Web のサポートは 1.3.0-alpha のみで、ファイルパスベースではなく、sessionStorage/OPFS を使用します。)このリファレンスでは、ストレージの選択と、2 つのエラー/パスに関する落とし穴を取り上げます。Preferences のキー、edit { }、Serializer<T> の基本は扱いません。Meet-Miyani/compose-skill を基にしています。MIT。関連項目: android-skills:android-data-layer、android-skills:kmp-boundaries、android-skills:kotlin-flows。

Preferences、Typed、Room の比較

必要なものストレージ
キーと値のフラグ(テーマ、ロケール、オンボーディング完了など)Preferences DataStore
1 つの型付きオブジェクト、多数の関連フィールド、スキーマの進化Typed DataStore + Serializer<T>
リレーショナルデータ、インデックス、WHERE/JOIN、100 件を超えるエントリー、ページングRoom
書き込みあたり約 50KB を超えるペイロードRoom/ファイルシステム — DataStore は edit のたびにファイル全体を書き換えます

目安:WHERE 句が役立つなら、Room を使ってください。

2 つの落とし穴

.catch は IOException のみに一致させてください。広範な catch は決して使わないでください。 何も指定しない catch { emit(emptyPreferences()) } は CancellationException を握りつぶし(構造化並行性を損ないます)、シリアライザー/破損エラーを、何も通知しない空の状態に隠してしまいます。

val settings: Flow<UserSettings> = dataStore.data
    .catch { e -> if (e is IOException) emit(emptyPreferences()) else throw e }
    .map { p -> UserSettings(p[Keys.DARK_MODE] ?: false, p[Keys.LOCALE] ?: "en") }

Typed DataStore の破損復旧がトリガーされるのは IOException ではなく CorruptionException です。 シリアライザーの readFrom は解析エラーを CorruptionException でラップする必要があり、ストアには ReplaceFileCorruptionHandler が必要です。これがないと、ファイルが 1 つ破損しただけで、以後すべての読み取りが永久に失敗します。

object AppSettingsSerializer : Serializer<AppSettings> {
    override val defaultValue = AppSettings()
    override suspend fun readFrom(input: InputStream): AppSettings =
        try { Json.decodeFromString(input.readBytes().decodeToString()) }
        catch (e: SerializationException) { throw CorruptionException("Cannot read AppSettings", e) }
    override suspend fun writeTo(t: AppSettings, output: OutputStream) =
        output.write(Json.encodeToString(t).encodeToByteArray())
}
val store = DataStoreFactory.create(
    serializer = AppSettingsSerializer,
    corruptionHandler = ReplaceFileCorruptionHandler { AppSettings() },
    produceFile = { File(context.filesDir, "app_settings.json") },
)

KMP ファクトリー — プラットフォームごとのパス(テンポラリディレクトリーではありません)

// commonMain
fun createPreferencesDataStore(producePath: () -> String): DataStore<Preferences> =
    PreferenceDataStoreFactory.createWithPath(produceFile = { producePath().toPath() })
// android: context.filesDir.resolve(PREFS_FILE).absolutePath
// ios:     NSDocumentDirectory via NSFileManager
// jvm:     File(System.getProperty("user.home"), ".myapp") — NOT java.io.tmpdir (the OS may wipe it on reboot)

(Composable 内で DataStore に runBlocking を使用しないでください。ディスク I/O 中にメインスレッドを停止させて ANR のリスクを高め、再コンポジションのたびに再実行されます。StateFlow を公開し、collectAsStateWithLifecycle で収集してください。)

コメント