App-Architektur: Datenschicht – Datenspeicher – Android-Entwickler

Project: /architecture/_project.yaml Book: /architecture/_book.yaml keywords: datastore, architecture, api:JetpackDataStore description: Explore this app architecture guide on data layer libraries to learn about Preferences DataStore and Proto DataStore, Setup, and more. hide_page_heading: true

DataStore   Teil von Android Jetpack.

Mit Kotlin Multiplatform testen
Mit Kotlin Multiplatform kann die Datenschicht für andere Plattformen freigegeben werden. DataStore in KMP einrichten und verwenden

Jetpack DataStore ist eine Datenspeicherlösung, mit der Sie Schlüssel/Wert-Paare oder typisierte Objekte mit Protocol Buffers speichern können. DataStore verwendet Kotlin-Coroutinen und Flow, um Daten asynchron, konsistent und transaktional zu speichern.

Wenn Sie SharedPreferences zum Speichern von Daten verwenden, sollten Sie stattdessen zu DataStore migrieren.

DataStore API

Die DataStore-Schnittstelle bietet die folgende API:

  1. Ein Flow, mit dem Daten aus dem DataStore gelesen werden können

    val data: Flow<T>
    
  2. Funktion zum Aktualisieren von Daten im DataStore

    suspend updateData(transform: suspend (t) -> T)
    

DataStore-Konfigurationen

Wenn Sie Daten mithilfe von Schlüsseln speichern und darauf zugreifen möchten, verwenden Sie die Preferences DataStore-Implementierung. Diese erfordert kein vordefiniertes Schema und bietet keine Typsicherheit. Sie hat eine API, die SharedPreferences ähnelt, aber nicht die Nachteile hat, die mit freigegebenen Einstellungen verbunden sind.

Mit DataStore können Sie benutzerdefinierte Klassen beibehalten. Dazu müssen Sie ein Schema für die Daten definieren und eine Serializer bereitstellen, um sie in ein persistierbares Format zu konvertieren. Sie können Protocol Buffers, JSON oder eine andere Serialisierungsstrategie verwenden.

Einrichten

Wenn Sie Jetpack DataStore in Ihrer App verwenden möchten, fügen Sie Ihrer Gradle-Datei je nach gewünschter Implementierung Folgendes hinzu:

Preferences DataStore

Fügen Sie der Datei „build.gradle“ die folgenden Zeilen hinzu:

Groovy

    dependencies {
        // Preferences DataStore (SharedPreferences like APIs)
        implementation "androidx.datastore:datastore-preferences:1.1.7"

        // Alternatively - without an Android dependency.
        implementation "androidx.datastore:datastore-preferences-core:1.1.7"
    }
    

Kotlin

    dependencies {
        // Preferences DataStore (SharedPreferences like APIs)
        implementation("androidx.datastore:datastore-preferences:1.1.7")

        // Alternatively - without an Android dependency.
        implementation("androidx.datastore:datastore-preferences-core:1.1.7")
    }
    

Wenn Sie die optionale RxJava-Unterstützung hinzufügen möchten, fügen Sie die folgenden Abhängigkeiten hinzu:

Groovy

    dependencies {
        // optional - RxJava2 support
        implementation "androidx.datastore:datastore-preferences-rxjava2:1.1.7"

        // optional - RxJava3 support
        implementation "androidx.datastore:datastore-preferences-rxjava3:1.1.7"
    }
    

Kotlin

    dependencies {
        // optional - RxJava2 support
        implementation("androidx.datastore:datastore-preferences-rxjava2:1.1.7")

        // optional - RxJava3 support
        implementation("androidx.datastore:datastore-preferences-rxjava3:1.1.7")
    }
    

DataStore

Fügen Sie der Datei „build.gradle“ die folgenden Zeilen hinzu:

Groovy

    dependencies {
        // Typed DataStore for custom data objects (for example, using Proto or JSON).
        implementation "androidx.datastore:datastore:1.1.7"

        // Alternatively - without an Android dependency.
        implementation "androidx.datastore:datastore-core:1.1.7"
    }
    

Kotlin

    dependencies {
        // Typed DataStore for custom data objects (for example, using Proto or JSON).
        implementation("androidx.datastore:datastore:1.1.7")

        // Alternatively - without an Android dependency.
        implementation("androidx.datastore:datastore-core:1.1.7")
    }
    

Fügen Sie die folgenden optionalen Abhängigkeiten für die RxJava-Unterstützung hinzu:

Groovy

    dependencies {
        // optional - RxJava2 support
        implementation "androidx.datastore:datastore-rxjava2:1.1.7"

        // optional - RxJava3 support
        implementation "androidx.datastore:datastore-rxjava3:1.1.7"
    }
    

Kotlin

    dependencies {
        // optional - RxJava2 support
        implementation("androidx.datastore:datastore-rxjava2:1.1.7")

        // optional - RxJava3 support
        implementation("androidx.datastore:datastore-rxjava3:1.1.7")
    }
    

Wenn Sie Inhalte serialisieren möchten, fügen Sie Abhängigkeiten für die Protokollzwischenspeicher- oder JSON-Serialisierung hinzu.

JSON-Serialisierung

Wenn Sie die JSON-Serialisierung verwenden möchten, fügen Sie Ihrer Gradle-Datei Folgendes hinzu:

Groovy

    plugins {
        id("org.jetbrains.kotlin.plugin.serialization") version "2.2.20"
    }

    dependencies {
        implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0"
    }
    

Kotlin

    plugins {
        id("org.jetbrains.kotlin.plugin.serialization") version "2.2.20"
    }

    dependencies {
        implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
    }
    

Protobuf-Serialisierung

Wenn Sie die Protobuf-Serialisierung verwenden möchten, fügen Sie Ihrer Gradle-Datei Folgendes hinzu:

Groovy

    plugins {
        id("com.google.protobuf") version "0.9.5"
    }
    dependencies {
        implementation "com.google.protobuf:protobuf-kotlin-lite:4.32.1"

    }

    protobuf {
        protoc {
            artifact = "com.google.protobuf:protoc:4.32.1"
        }
        generateProtoTasks {
            all().forEach { task ->
                task.builtins {
                    create("java") {
                        option("lite")
                    }
                    create("kotlin")
                }
            }
        }
    }
    

Kotlin

    plugins {
        id("com.google.protobuf") version "0.9.5"
    }
    dependencies {
        implementation("com.google.protobuf:protobuf-kotlin-lite:4.32.1")
    }

    protobuf {
        protoc {
            artifact = "com.google.protobuf:protoc:4.32.1"
        }
        generateProtoTasks {
            all().forEach { task ->
                task.builtins {
                    create("java") {
                        option("lite")
                    }
                    create("kotlin")
                }
            }
        }
    }
    

DataStore richtig verwenden

Damit Sie DataStore richtig verwenden, sollten Sie immer die folgenden Regeln beachten:

  1. Erstellen Sie niemals mehr als eine Instanz von DataStore für eine bestimmte Datei im selben Prozess. Dadurch kann die gesamte DataStore-Funktionalität beeinträchtigt werden. Wenn für eine bestimmte Datei im selben Prozess mehrere DataStores aktiv sind, wird beim Lesen oder Aktualisieren von Daten eine IllegalStateException ausgelöst.

  2. Der generische Typ von DataStore<T> muss unveränderlich sein. Wenn Sie einen Typ ändern, der in DataStore verwendet wird, wird die von DataStore bereitgestellte Konsistenz ungültig und es können potenziell schwerwiegende, schwer zu erkennende Fehler auftreten. Wir empfehlen die Verwendung von Protocol Buffers, da sie für Unveränderlichkeit, eine übersichtliche API und eine effiziente Serialisierung sorgen.

  3. Verwenden Sie nicht gleichzeitig SingleProcessDataStore und MultiProcessDataStore für dieselbe Datei. Wenn Sie von mehr als einem Prozess auf DataStore zugreifen möchten, müssen Sie MultiProcessDataStore verwenden.

Datendefinition

Preferences DataStore

Definieren Sie einen Schlüssel, der zum Speichern von Daten auf der Festplatte verwendet wird.

val EXAMPLE_COUNTER = intPreferencesKey("example_counter")

JSON-Datastore

Fügen Sie für den JSON-Datenspeicher den Daten, die Sie beibehalten möchten, die Annotation @Serialization hinzu.

@Serializable
data class Settings(
    val exampleCounter: Int
)

Definieren Sie eine Klasse, die Serializer<T> implementiert, wobei T der Typ der Klasse ist, der Sie die Annotation zuvor hinzugefügt haben. Achten Sie darauf, einen Standardwert für den Serializer anzugeben, der verwendet werden soll, wenn noch keine Datei erstellt wurde.

object SettingsSerializer : Serializer<Settings> {

    override val defaultValue: Settings = Settings(exampleCounter = 0)

    override suspend fun readFrom(input: InputStream): Settings =
        try {
            Json.decodeFromString<Settings>(
                input.readBytes().decodeToString()
            )
        } catch (serialization: SerializationException) {
            throw CorruptionException("Unable to read Settings", serialization)
        }

    override suspend fun writeTo(t: Settings, output: OutputStream) {
        output.write(
            Json.encodeToString(t)
                .encodeToByteArray()
        )
    }
}

Proto DataStore

Die Proto DataStore-Implementierung verwendet DataStore und Protobufs, um typisierte Objekte auf der Festplatte zu speichern.

Für Proto DataStore ist ein vordefiniertes Schema in einer Protobuf-Datei im Verzeichnis app/src/main/proto/ erforderlich. Dieses Schema definiert den Typ für die Objekte, die Sie in Ihrem Proto DataStore speichern. Weitere Informationen zum Definieren eines Proto-Schemas finden Sie im Sprachleitfaden für Protokollpuffer.

Fügen Sie im Ordner src/main/proto eine Datei mit dem Namen „settings.proto“ hinzu:

syntax = "proto3";

option java_package = "com.example.datastore.snippets.proto";
option java_multiple_files = true;

message Settings {
  int32 example_counter = 1;
}

Definieren Sie eine Klasse, die Serializer<T> implementiert, wobei T der in der Proto-Datei definierte Typ ist. Diese Serializer-Klasse definiert, wie DataStore Ihren Datentyp liest und schreibt. Geben Sie einen Standardwert für den Serializer an, der verwendet werden soll, wenn noch keine Datei erstellt wurde.

object SettingsSerializer : Serializer<Settings> {
    override val defaultValue: Settings = Settings.getDefaultInstance()

    override suspend fun readFrom(input: InputStream): Settings {
        try {
            return Settings.parseFrom(input)
        } catch (exception: InvalidProtocolBufferException) {
            throw CorruptionException("Cannot read proto.", exception)
        }
    }

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

Datenspeicher erstellen

Sie müssen einen Namen für die Datei angeben, in der die Daten gespeichert werden.

Preferences DataStore

Die Preferences DataStore-Implementierung verwendet die Klassen DataStore und Preferences, um Schlüssel/Wert-Paare auf der Festplatte zu speichern. Verwenden Sie den von preferencesDataStore erstellten Property-Delegaten, um eine Instanz von DataStore<Preferences> zu erstellen. Rufen Sie sie einmal auf der obersten Ebene Ihrer Kotlin-Datei auf. Greifen Sie über diese Property im Rest Ihrer Anwendung auf DataStore zu. So lässt sich Ihr DataStore leichter als Singleton beibehalten. Wenn Sie RxJava verwenden, können Sie stattdessen RxPreferenceDataStoreBuilder verwenden. Der obligatorische Parameter name ist der Name des Preferences DataStore.

// At the top level of your kotlin file:
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")

JSON-Datastore

Verwenden Sie den von dataStore erstellten Attribut-Delegate, um eine Instanz von DataStore<T> zu erstellen, wobei T die serialisierbare Datenklasse ist. Rufen Sie sie einmal auf der obersten Ebene Ihrer Kotlin-Datei auf und greifen Sie über diese Eigenschaftsdelegierung im Rest Ihrer App darauf zu. Der Parameter fileName gibt an, welche Datei DataStore zum Speichern der Daten verwenden soll, und der Parameter serializer gibt den Namen der in Schritt 1 definierten Serializer-Klasse an.

val Context.dataStore: DataStore<Settings> by dataStore(
    fileName = "settings.json",
    serializer = SettingsSerializer,
)

Proto DataStore

Verwenden Sie den von dataStore erstellten Attribut-Delegate, um eine Instanz von DataStore<T> zu erstellen. Dabei ist T der in der Proto-Datei definierte Typ. Rufen Sie die Funktion einmal auf der obersten Ebene Ihrer Kotlin-Datei auf und greifen Sie über diesen Property-Delegate im Rest Ihrer App darauf zu. Der Parameter fileName gibt an, welche Datei DataStore zum Speichern der Daten verwenden soll, und der Parameter serializer gibt den Namen der Serializer-Klasse an, die in Schritt 1 definiert wurde.

val Context.dataStore: DataStore<Settings> by dataStore(
    fileName = "settings.pb",
    serializer = SettingsSerializer,
)

Aus DataStore lesen

Sie müssen einen Namen für die Datei angeben, in der die Daten gespeichert werden.

Preferences DataStore

Da Preferences DataStore kein vordefiniertes Schema verwendet, müssen Sie mit der entsprechenden Schlüsselfunktion einen Schlüssel für jeden Wert definieren, den Sie in der DataStore<Preferences>-Instanz speichern möchten. Wenn Sie beispielsweise einen Schlüssel für einen Ganzzahlwert definieren möchten, verwenden Sie intPreferencesKey(). Verwenden Sie dann die Eigenschaft DataStore.data, um den entsprechenden gespeicherten Wert über einen Flow verfügbar zu machen.

fun counterFlow(): Flow<Int> = context.dataStore.data.map { preferences ->
    preferences[EXAMPLE_COUNTER] ?: 0
}

JSON-Datastore

Verwenden Sie DataStore.data, um eine Flow der entsprechenden Eigenschaft aus Ihrem gespeicherten Objekt verfügbar zu machen.

fun counterFlow(): Flow<Int> = context.dataStore.data.map { settings ->
    settings.exampleCounter
}

Proto DataStore

Verwenden Sie DataStore.data, um eine Flow der entsprechenden Eigenschaft aus Ihrem gespeicherten Objekt verfügbar zu machen.

fun counterFlow(): Flow<Int> = context.dataStore.data.map { settings ->
    settings.exampleCounter
}

In DataStore schreiben

DataStore bietet die Funktion updateData(), mit der ein gespeichertes Objekt transaktional aktualisiert wird. updateData gibt den aktuellen Status der Daten als Instanz Ihres Datentyps zurück und aktualisiert die Daten transaktional in einem atomaren Lese-/Schreib-/Änderungsvorgang. Der gesamte Code im updateData-Block wird als eine einzelne Transaktion behandelt.

Preferences DataStore

suspend fun incrementCounter() {
    context.dataStore.updateData {
        it.toMutablePreferences().also { preferences ->
            preferences[EXAMPLE_COUNTER] = (preferences[EXAMPLE_COUNTER] ?: 0) + 1
        }
    }
}

JSON-Datastore

suspend fun incrementCounter() {
    context.dataStore.updateData { settings ->
        settings.copy(exampleCounter = settings.exampleCounter + 1)
    }
}

Proto DataStore

suspend fun incrementCounter() {
    context.dataStore.updateData { settings ->
        settings.copy { exampleCounter = exampleCounter + 1 }
    }
}

Beispiel erstellen

Sie können diese Funktionen in einer Klasse zusammenfassen und in einer Compose-App verwenden.

Preferences DataStore

Wir können diese Funktionen jetzt in eine Klasse namens PreferencesDataStore einfügen und in einer Compose-App verwenden.

val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val preferencesDataStore = remember(context) { PreferencesDataStore(context) }

// Display counter value.
val exampleCounter by preferencesDataStore.counterFlow()
    .collectAsState(initial = 0, coroutineScope.coroutineContext)
Text(
    text = "Counter $exampleCounter",
    fontSize = 25.sp
)

// Update the counter.
Button(
    onClick = {
        coroutineScope.launch { preferencesDataStore.incrementCounter() }
    }
) {
    Text("increment")
}

JSON-Datastore

Wir können diese Funktionen jetzt in eine Klasse namens JSONDataStore einfügen und in einer Compose-App verwenden.

val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val jsonDataStore = remember(context) { JsonDataStore(context) }

// Display counter value.
val exampleCounter by jsonDataStore.counterFlow()
    .collectAsState(initial = 0, coroutineScope.coroutineContext)
Text(
    text = "Counter $exampleCounter",
    fontSize = 25.sp
)

// Update the counter.
Button(onClick = { coroutineScope.launch { jsonDataStore.incrementCounter() } }) {
    Text("increment")
}

Proto DataStore

Wir können diese Funktionen jetzt in eine Klasse namens ProtoDataStore einfügen und in einer Compose-App verwenden.

val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val protoDataStore = remember(context) { ProtoDataStore(context) }

// Display counter value.
val exampleCounter by protoDataStore.counterFlow()
    .collectAsState(initial = 0, coroutineScope.coroutineContext)
Text(
    text = "Counter $exampleCounter",
    fontSize = 25.sp
)

// Update the counter.
Button(onClick = { coroutineScope.launch { protoDataStore.incrementCounter() } }) {
    Text("increment")
}

DataStore in synchronem Code verwenden

Einer der Hauptvorteile von DataStore ist die asynchrone API. Es ist jedoch möglicherweise nicht immer möglich, den umgebenden Code so zu ändern, dass er asynchron ist. Das kann der Fall sein, wenn Sie mit einer vorhandenen Codebasis arbeiten, die synchrone Festplatten-E/A verwendet, oder wenn Sie eine Abhängigkeit haben, die keine asynchrone API bietet.

Kotlin-Coroutinen bieten den Coroutinen-Builder runBlocking(), um die Lücke zwischen synchronem und asynchronem Code zu schließen. Mit runBlocking() können Sie Daten synchron aus DataStore lesen. RxJava bietet blockierende Methoden für Flowable. Der folgende Code blockiert den aufrufenden Thread, bis DataStore Daten zurückgibt:

Kotlin

val exampleData = runBlocking { context.dataStore.data.first() }

Java

Settings settings = dataStore.data().blockingFirst();

Wenn synchrone E/A-Vorgänge im UI-Thread ausgeführt werden, kann dies zu ANR-Fehlern oder einer nicht reagierenden Benutzeroberfläche führen. Sie können diese Probleme umgehen, indem Sie die Daten aus DataStore asynchron vorab laden:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    lifecycleScope.launch {
        context.dataStore.data.first()
        // You should also handle IOExceptions here.
    }
}

Java

dataStore.data().first().subscribe();

Auf diese Weise liest DataStore die Daten asynchron und speichert sie im Cache. Spätere synchrone Lesevorgänge mit runBlocking() können schneller sein oder eine Datenträger-E/A-Operation ganz vermeiden, wenn der erste Lesevorgang abgeschlossen ist.

DataStore in Code mit mehreren Prozessen verwenden

Sie können DataStore so konfigurieren, dass in verschiedenen Prozessen auf dieselben Daten zugegriffen wird, mit denselben Datenkonsistenzeigenschaften wie in einem einzelnen Prozess. DataStore bietet insbesondere Folgendes:

  • Bei Lesevorgängen werden nur die Daten zurückgegeben, die auf der Festplatte gespeichert wurden.
  • Read-after-Write-Konsistenz.
  • Schreibvorgänge werden serialisiert.
  • Lesevorgänge werden nie durch Schreibvorgänge blockiert.

Betrachten Sie eine Beispielanwendung mit einem Dienst und einer Aktivität, in der der Dienst in einem separaten Prozess ausgeführt wird und den DataStore regelmäßig aktualisiert.

In diesem Beispiel wird ein JSON-Datastore verwendet. Sie können aber auch einen Preferences- oder Proto-Datastore verwenden.

@Serializable
data class Time(
    val lastUpdateMillis: Long
)

Ein Serializer teilt DataStore mit, wie Ihr Datentyp gelesen und geschrieben werden soll. Achten Sie darauf, dass Sie einen Standardwert für den Serializer angeben, der verwendet werden soll, wenn noch keine Datei erstellt wurde. Im Folgenden finden Sie ein Beispiel für die Implementierung mit kotlinx.serialization:

object TimeSerializer : Serializer<Time> {

    override val defaultValue: Time = Time(lastUpdateMillis = 0L)

    override suspend fun readFrom(input: InputStream): Time =
        try {
            Json.decodeFromString<Time>(
                input.readBytes().decodeToString()
            )
        } catch (serialization: SerializationException) {
            throw CorruptionException("Unable to read Time", serialization)
        }

    override suspend fun writeTo(t: Time, output: OutputStream) {
        output.write(
            Json.encodeToString(t)
                .encodeToByteArray()
        )
    }
}

Damit Sie DataStore in verschiedenen Prozessen verwenden können, müssen Sie das DataStore-Objekt mit MultiProcessDataStoreFactory für den App- und den Dienstcode erstellen:

val dataStore = MultiProcessDataStoreFactory.create(
    serializer = TimeSerializer,
    produceFile = {
        File("${context.cacheDir.path}/time.pb")
    },
    corruptionHandler = null
)

Fügen Sie zum AndroidManifiest.xml Folgendes hinzu:

<service
    android:name=".TimestampUpdateService"
    android:process=":my_process_id" />

Der Dienst ruft regelmäßig updateLastUpdateTime() auf, das mit updateData in den Datenspeicher schreibt.

suspend fun updateLastUpdateTime() {
    dataStore.updateData { time ->
        time.copy(lastUpdateMillis = System.currentTimeMillis())
    }
}

Die App liest den vom Dienst geschriebenen Wert über den Datenfluss:

fun timeFlow(): Flow<Long> = dataStore.data.map { time ->
    time.lastUpdateMillis
}

Jetzt können wir alle diese Funktionen in einer Klasse namens MultiProcessDataStore zusammenfassen und in einer App verwenden.

Hier ist der Dienstcode:

class TimestampUpdateService : Service() {
    val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
    val multiProcessDataStore by lazy { MultiProcessDataStore(applicationContext) }


    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        serviceScope.launch {
            while (true) {
                multiProcessDataStore.updateLastUpdateTime()
                delay(1000)
            }
        }
        return START_NOT_STICKY
    }

    override fun onDestroy() {
        super.onDestroy()
        serviceScope.cancel()
    }
}

Und der App-Code:

val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val multiProcessDataStore = remember(context) { MultiProcessDataStore(context) }

// Display time written by other process.
val lastUpdateTime by multiProcessDataStore.timeFlow()
    .collectAsState(initial = 0, coroutineScope.coroutineContext)
Text(
    text = "Last updated: $lastUpdateTime",
    fontSize = 25.sp
)

DisposableEffect(context) {
    val serviceIntent = Intent(context, TimestampUpdateService::class.java)
    context.startService(serviceIntent)
    onDispose {
        context.stopService(serviceIntent)
    }
}

Sie können die Hilt-Abhängigkeitsinjektion verwenden, damit Ihre DataStore-Instanz pro Prozess eindeutig ist:

@Provides
@Singleton
fun provideDataStore(@ApplicationContext context: Context): DataStore<Settings> =
   MultiProcessDataStoreFactory.create(...)

Umgang mit beschädigten Dateien

In seltenen Fällen kann die persistente Datei auf dem Datenträger von DataStore beschädigt werden. Standardmäßig wird DataStore nicht automatisch nach einer Beschädigung wiederhergestellt. Versuche, Daten daraus zu lesen, führen dazu, dass das System eine CorruptionException auslöst.

DataStore bietet eine API für die Verarbeitung von Beschädigungen, mit der Sie sich in einem solchen Fall ordnungsgemäß erholen und das Auslösen der Ausnahme vermeiden können. Wenn der Handler für beschädigte Dateien konfiguriert ist, ersetzt er die beschädigte Datei durch eine neue Datei mit einem vordefinierten Standardwert.

Um diesen Handler einzurichten, geben Sie beim Erstellen der DataStore-Instanz in by dataStore() oder in der Factory-Methode DataStoreFactory eine corruptionHandler an:

val dataStore: DataStore<Settings> = DataStoreFactory.create(
   serializer = SettingsSerializer(),
   produceFile = {
       File("${context.cacheDir.path}/myapp.preferences_pb")
   },
   corruptionHandler = ReplaceFileCorruptionHandler { Settings(lastUpdate = 0) }
)

Feedback geben

Über diese Ressourcen können Sie uns Ihr Feedback und Ihre Ideen mitteilen:

Problemverfolgung:
Probleme melden, damit wir Fehler beheben können.

Zusätzliche Ressourcen

Weitere Informationen zu Jetpack DataStore finden Sie in den folgenden zusätzlichen Ressourcen:

Produktproben

Blogs

Codelabs