From 3ea0a8977d4d9959270ae0059d741c38f608b443 Mon Sep 17 00:00:00 2001 From: Ralston Da Silva Date: Thu, 16 Oct 2025 13:38:36 -0700 Subject: [PATCH] Add a new project for DataStore The data store details on DAC has inline code snippets https://developer.android.com/topic/libraries/architecture/datastore This PR adds code samples that can be used as snippets on DAC. --- datastore/.gitignore | 1 + datastore/build.gradle.kts | 120 ++++++++++++ datastore/proguard-rules.pro | 21 ++ .../snippets/DataStoreSnippetsTest.kt | 63 ++++++ datastore/src/main/AndroidManifest.xml | 42 ++++ .../com/example/datastore/snippets/Home.kt | 58 ++++++ .../datastore/snippets/MainActivity.kt | 102 ++++++++++ .../snippets/TimestampUpdateService.kt | 54 +++++ .../datastore/snippets/json/JsonDataStore.kt | 84 ++++++++ .../snippets/json/JsonDataStoreScreen.kt | 61 ++++++ .../multiprocess/MultiProcessDataStore.kt | 97 +++++++++ .../MultiProcessDataStoreScreen.kt | 66 +++++++ .../preferences/PreferencesDataStore.kt | 67 +++++++ .../preferences/PreferencesDataStoreScreen.kt | 76 +++++++ .../snippets/proto/ProtoDataStore.kt | 70 +++++++ .../snippets/proto/ProtoDataStoreScreen.kt | 61 ++++++ .../datastore/snippets/ui/theme/Color.kt | 27 +++ .../datastore/snippets/ui/theme/Theme.kt | 73 +++++++ .../datastore/snippets/ui/theme/Type.kt | 50 +++++ datastore/src/main/proto/settings.proto | 10 + .../drawable-v24/ic_launcher_foreground.xml | 46 +++++ .../res/drawable/ic_launcher_background.xml | 185 ++++++++++++++++++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 21 ++ .../mipmap-anydpi-v26/ic_launcher_round.xml | 21 ++ .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes datastore/src/main/res/values/colors.xml | 25 +++ datastore/src/main/res/values/strings.xml | 19 ++ datastore/src/main/res/values/themes.xml | 20 ++ gradle/libs.versions.toml | 17 ++ settings.gradle.kts | 1 + 39 files changed, 1558 insertions(+) create mode 100644 datastore/.gitignore create mode 100644 datastore/build.gradle.kts create mode 100644 datastore/proguard-rules.pro create mode 100644 datastore/src/androidTest/java/com/example/datastore/snippets/DataStoreSnippetsTest.kt create mode 100644 datastore/src/main/AndroidManifest.xml create mode 100644 datastore/src/main/java/com/example/datastore/snippets/Home.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/MainActivity.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/TimestampUpdateService.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/json/JsonDataStore.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/json/JsonDataStoreScreen.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/multiprocess/MultiProcessDataStore.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/multiprocess/MultiProcessDataStoreScreen.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/preferences/PreferencesDataStore.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/preferences/PreferencesDataStoreScreen.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/proto/ProtoDataStore.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/proto/ProtoDataStoreScreen.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/ui/theme/Color.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/ui/theme/Theme.kt create mode 100644 datastore/src/main/java/com/example/datastore/snippets/ui/theme/Type.kt create mode 100644 datastore/src/main/proto/settings.proto create mode 100644 datastore/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 datastore/src/main/res/drawable/ic_launcher_background.xml create mode 100644 datastore/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 datastore/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 datastore/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 datastore/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 datastore/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 datastore/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 datastore/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 datastore/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 datastore/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 datastore/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 datastore/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 datastore/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 datastore/src/main/res/values/colors.xml create mode 100644 datastore/src/main/res/values/strings.xml create mode 100644 datastore/src/main/res/values/themes.xml diff --git a/datastore/.gitignore b/datastore/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/datastore/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/datastore/build.gradle.kts b/datastore/build.gradle.kts new file mode 100644 index 000000000..9d5484f9f --- /dev/null +++ b/datastore/build.gradle.kts @@ -0,0 +1,120 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.compose.compiler) + + // [START android_datastore_proto_plugin] + alias(libs.plugins.google.protobuf) + // [END android_datastore_proto_plugin] + + // [START android_datastore_serialization_plugin] + alias(libs.plugins.kotlin.serialization) + // [END android_datastore_serialization_plugin] +} + +android { + namespace = "com.example.datastore.snippets" + compileSdk = 36 + + defaultConfig { + applicationId = "com.example.datastore.snippets" + minSdk = 23 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.ui.graphics) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material3) + + // [START android_datastore_dependency] + // Typed DataStore (Typed API surface, such as Proto) + implementation(libs.androidx.datastore) + + // Alternatively - without an Android dependency. + implementation(libs.androidx.datastore.core) + // [END android_datastore_dependency] + + // [START android_datastore_preferences_dependency] + // Preferences DataStore (SharedPreferences like APIs) + implementation(libs.androidx.datastore.preferences) + + // Alternatively - without an Android dependency. + implementation(libs.androidx.datastore.preferences.core) + // [END android_datastore_preferences_dependency] + + // [START android_datastore_preferences_dependency_rxjava] + // optional - RxJava2 support + implementation(libs.androidx.datastore.preferences.rxjava2) + + // optional - RxJava3 support + implementation(libs.androidx.datastore.preferences.rxjava3) + // [END android_datastore_preferences_dependency_rxjava] + + implementation(libs.androidx.navigation3.ui) + implementation(libs.androidx.navigation3.runtime) + + // [START android_datastore_proto_dependency] + implementation(libs.google.protobuf.kotlin.lite) + // [END android_datastore_proto_dependency] + + // [START android_datastore_json_dependency] + implementation(libs.kotlinx.serialization.json) + // [END android_datastore_json_dependency] + + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.test.ext.junit) + androidTestImplementation(libs.androidx.test.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.compose.ui.test.junit4) + debugImplementation(libs.androidx.compose.ui.tooling) + debugImplementation(libs.androidx.compose.ui.test.manifest) +} + +// [START android_datastore_proto_task] +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:4.32.1" + } + generateProtoTasks { + all().forEach { task -> + task.builtins { + create("java") { + option("lite") + } + create("kotlin") + } + } + } +} +// [END android_datastore_proto_task] \ No newline at end of file diff --git a/datastore/proguard-rules.pro b/datastore/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/datastore/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/datastore/src/androidTest/java/com/example/datastore/snippets/DataStoreSnippetsTest.kt b/datastore/src/androidTest/java/com/example/datastore/snippets/DataStoreSnippetsTest.kt new file mode 100644 index 000000000..6163fe03e --- /dev/null +++ b/datastore/src/androidTest/java/com/example/datastore/snippets/DataStoreSnippetsTest.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.datastore.snippets + +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.example.datastore.snippets.json.JsonDataStoreScreen +import com.example.datastore.snippets.multiprocess.MultiProcessDataStoreScreen +import com.example.datastore.snippets.preferences.PreferencesDataStoreScreen +import com.example.datastore.snippets.proto.ProtoDataStoreScreen +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class DataStoreSnippetsTest { + @get:Rule + val rule = createComposeRule() + + @Test + fun launchPreferencesDataStore() { + rule.setContent { PreferencesDataStoreScreen() } + rule.onNodeWithText("Preferences DataStore").assertExists() + } + + @Test + fun launchProtoDataStore() { + rule.setContent { ProtoDataStoreScreen() } + rule.onNodeWithText("Proto DataStore").assertExists() + } + + @Test + fun launchJsonDataStore() { + rule.setContent { JsonDataStoreScreen() } + rule.onNodeWithText("Json DataStore").assertExists() + } + + @Test + fun launchMultiProcessDataStore() { + rule.setContent { MultiProcessDataStoreScreen() } + rule.onNodeWithText("Multi-process DataStore").assertExists() + } +} diff --git a/datastore/src/main/AndroidManifest.xml b/datastore/src/main/AndroidManifest.xml new file mode 100644 index 000000000..7ca446743 --- /dev/null +++ b/datastore/src/main/AndroidManifest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + diff --git a/datastore/src/main/java/com/example/datastore/snippets/Home.kt b/datastore/src/main/java/com/example/datastore/snippets/Home.kt new file mode 100644 index 000000000..a014c65ac --- /dev/null +++ b/datastore/src/main/java/com/example/datastore/snippets/Home.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.datastore.snippets + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +internal fun Home(backStack: MutableList) { + Column { + Item("Preferences Data Store") { + backStack.add(MainActivity.Snippets.PreferencesDataStore) + } + Item("Proto Data Store") { + backStack.add(MainActivity.Snippets.ProtoDataStore) + } + Item("Json Data Store") { + backStack.add(MainActivity.Snippets.JsonDataStore) + } + Item("Multi process Data Store") { + backStack.add(MainActivity.Snippets.MultiProcessDataStore) + } + } +} + +@Composable +private fun Item(text: String, onClick: () -> Unit) { + Box( + Modifier + .fillMaxWidth() + .clickable(onClick = onClick) + .padding(10.dp) + ) { + Text(fontSize = 30.sp, text = text) + } +} \ No newline at end of file diff --git a/datastore/src/main/java/com/example/datastore/snippets/MainActivity.kt b/datastore/src/main/java/com/example/datastore/snippets/MainActivity.kt new file mode 100644 index 000000000..3ac44d81b --- /dev/null +++ b/datastore/src/main/java/com/example/datastore/snippets/MainActivity.kt @@ -0,0 +1,102 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.datastore.snippets + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.navigation3.runtime.NavEntry +import androidx.navigation3.ui.NavDisplay +import com.example.datastore.snippets.MainActivity.Snippets.JsonDataStore +import com.example.datastore.snippets.MainActivity.Snippets.LandingPage +import com.example.datastore.snippets.MainActivity.Snippets.MultiProcessDataStore +import com.example.datastore.snippets.MainActivity.Snippets.PreferencesDataStore +import com.example.datastore.snippets.MainActivity.Snippets.ProtoDataStore +import com.example.datastore.snippets.json.JsonDataStoreScreen +import com.example.datastore.snippets.multiprocess.MultiProcessDataStoreScreen +import com.example.datastore.snippets.preferences.PreferencesDataStoreScreen +import com.example.datastore.snippets.proto.ProtoDataStoreScreen +import com.example.datastore.snippets.ui.theme.SnippetsTheme + +class MainActivity : ComponentActivity() { + + internal enum class Snippets { LandingPage, PreferencesDataStore, ProtoDataStore, JsonDataStore, MultiProcessDataStore } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + SnippetsTheme { + Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> + val backStack = remember { mutableStateListOf(LandingPage) } + NavDisplay( + modifier = Modifier.padding(innerPadding), + backStack = backStack + ) { + when (it) { + LandingPage -> NavEntry(LandingPage) { + Home(backStack) + } + + PreferencesDataStore -> NavEntry(PreferencesDataStore) { + PreferencesDataStoreScreen() + } + + ProtoDataStore -> NavEntry(ProtoDataStore) { + ProtoDataStoreScreen() + } + + JsonDataStore -> NavEntry(JsonDataStore) { + JsonDataStoreScreen() + } + + MultiProcessDataStore -> NavEntry(MultiProcessDataStore) { + MultiProcessDataStoreScreen() + } + } + } + } + } + } + } +} + +@Composable +fun Greeting(name: String, modifier: Modifier = Modifier) { + Text( + text = "Hello $name!", + modifier = modifier + ) +} + +@Preview(showBackground = true) +@Composable +fun GreetingPreview() { + SnippetsTheme { + Greeting("Android") + } +} \ No newline at end of file diff --git a/datastore/src/main/java/com/example/datastore/snippets/TimestampUpdateService.kt b/datastore/src/main/java/com/example/datastore/snippets/TimestampUpdateService.kt new file mode 100644 index 000000000..9b10afc5c --- /dev/null +++ b/datastore/src/main/java/com/example/datastore/snippets/TimestampUpdateService.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.datastore.snippets + +import android.app.Service +import android.content.Intent +import android.os.IBinder +import com.example.datastore.snippets.multiprocess.MultiProcessDataStore +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +// [START android_datastore_multiprocess_service] +class TimestampUpdateService : Service() { + val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + val multiProcessDataStore by lazy { MultiProcessDataStore(applicationContext) } + + // [START_EXCLUDE silent] + override fun onBind(intent: Intent): IBinder? = null + // [END_EXCLUDE silent] + + 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() + } +} +// [END android_datastore_multiprocess_service] diff --git a/datastore/src/main/java/com/example/datastore/snippets/json/JsonDataStore.kt b/datastore/src/main/java/com/example/datastore/snippets/json/JsonDataStore.kt new file mode 100644 index 000000000..a73d0a431 --- /dev/null +++ b/datastore/src/main/java/com/example/datastore/snippets/json/JsonDataStore.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.datastore.snippets.json + +import android.content.Context +import androidx.datastore.core.CorruptionException +import androidx.datastore.core.DataStore +import androidx.datastore.core.Serializer +import androidx.datastore.dataStore +import java.io.InputStream +import java.io.OutputStream +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationException +import kotlinx.serialization.json.Json + +// [START android_datastore_json_create] +val Context.dataStore: DataStore by dataStore( + fileName = "settings.json", + serializer = SettingsSerializer, +) +// [END android_datastore_json_create] + +class JsonDataStore(private val context: Context) { + + // [START android_datastore_json_read] + fun counterFlow(): Flow = context.dataStore.data.map { settings -> + settings.exampleCounter + } + // [END android_datastore_json_read] + + // [START android_datastore_json_write] + suspend fun incrementCounter() { + context.dataStore.updateData { settings -> + settings.copy(exampleCounter = settings.exampleCounter + 1) + } + } + // [END android_datastore_json_write] +} + +// [START android_datastore_json_definition] +@Serializable +data class Settings( + val exampleCounter: Int +) +// [END android_datastore_json_definition] + +// [START android_datastore_json_serializer] +object SettingsSerializer : Serializer { + + override val defaultValue: Settings = Settings(exampleCounter = 0) + + override suspend fun readFrom(input: InputStream): Settings = + try { + Json.decodeFromString( + 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() + ) + } +} +// [END android_datastore_json_serializer] diff --git a/datastore/src/main/java/com/example/datastore/snippets/json/JsonDataStoreScreen.kt b/datastore/src/main/java/com/example/datastore/snippets/json/JsonDataStoreScreen.kt new file mode 100644 index 000000000..916b60a67 --- /dev/null +++ b/datastore/src/main/java/com/example/datastore/snippets/json/JsonDataStoreScreen.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.datastore.snippets.json + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.sp +import kotlinx.coroutines.launch + +@Preview(showBackground = true) +@Composable +internal fun JsonDataStoreScreen() { + Column(Modifier.fillMaxSize()) { + Text( + text = "Json DataStore", + fontSize = 30.sp + ) + // [START android_datastore_json_compose_sample] + 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") + } + // [END android_datastore_json_compose_sample] + } +} \ No newline at end of file diff --git a/datastore/src/main/java/com/example/datastore/snippets/multiprocess/MultiProcessDataStore.kt b/datastore/src/main/java/com/example/datastore/snippets/multiprocess/MultiProcessDataStore.kt new file mode 100644 index 000000000..b677c872e --- /dev/null +++ b/datastore/src/main/java/com/example/datastore/snippets/multiprocess/MultiProcessDataStore.kt @@ -0,0 +1,97 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.datastore.snippets.multiprocess + +import android.content.Context +import androidx.datastore.core.CorruptionException +import androidx.datastore.core.DataStore +import androidx.datastore.core.MultiProcessDataStoreFactory +import androidx.datastore.core.Serializer +import java.io.File +import java.io.InputStream +import java.io.OutputStream +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationException +import kotlinx.serialization.json.Json + +fun createMultiProcessDataStore(context: Context): DataStore