Make the PreferencesDataStore factory easier to use and make both Factories objects instead of classes.
Test: All current DataStore tests as well as a new test for the newly added function in PreferenceDataStoreTest
Bug: 163595491
RelNote: Make DataStore factories easier to use
Change-Id: I2f28a5eca2f9fb3a3faa222664430ae2c0098fb6
diff --git a/datastore/datastore-core/api/api_lint.ignore b/datastore/datastore-core/api/api_lint.ignore
index 8b7d447..f65d316 100644
--- a/datastore/datastore-core/api/api_lint.ignore
+++ b/datastore/datastore-core/api/api_lint.ignore
@@ -1,6 +1,4 @@
// Baseline format: 1.0
-MissingJvmstatic: androidx.datastore.migrations.SharedPreferencesMigration#SharedPreferencesMigration(android.content.Context, String, androidx.datastore.migrations.MigrationFromSharedPreferences<T>, java.util.Set<java.lang.String>, boolean):
- A Kotlin method with default parameter values should be annotated with @JvmOverloads for better Java interoperability; see https://android.github.io/kotlin-guides/interop.html#function-overloads-for-defaults
MissingJvmstatic: androidx.datastore.migrations.SharedPreferencesView#getString(String, String):
A Kotlin method with default parameter values should be annotated with @JvmOverloads for better Java interoperability; see https://android.github.io/kotlin-guides/interop.html#function-overloads-for-defaults
MissingJvmstatic: androidx.datastore.migrations.SharedPreferencesView#getStringSet(String, java.util.Set<java.lang.String>):
diff --git a/datastore/datastore-core/api/current.txt b/datastore/datastore-core/api/current.txt
index 80f8b50..34756f70 100644
--- a/datastore/datastore-core/api/current.txt
+++ b/datastore/datastore-core/api/current.txt
@@ -22,11 +22,15 @@
}
public final class DataStoreFactory {
- ctor public DataStoreFactory();
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf());
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null);
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer);
+ field public static final androidx.datastore.DataStoreFactory INSTANCE;
+ }
+
+ public final class DataStoreFactoryKt {
+ method public static <T> androidx.datastore.DataStore<T> createDataStore(android.content.Context, String fileName, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
}
public interface Serializer<T> {
diff --git a/datastore/datastore-core/api/public_plus_experimental_current.txt b/datastore/datastore-core/api/public_plus_experimental_current.txt
index 80f8b50..34756f70 100644
--- a/datastore/datastore-core/api/public_plus_experimental_current.txt
+++ b/datastore/datastore-core/api/public_plus_experimental_current.txt
@@ -22,11 +22,15 @@
}
public final class DataStoreFactory {
- ctor public DataStoreFactory();
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf());
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null);
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer);
+ field public static final androidx.datastore.DataStoreFactory INSTANCE;
+ }
+
+ public final class DataStoreFactoryKt {
+ method public static <T> androidx.datastore.DataStore<T> createDataStore(android.content.Context, String fileName, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
}
public interface Serializer<T> {
diff --git a/datastore/datastore-core/api/restricted_current.txt b/datastore/datastore-core/api/restricted_current.txt
index 80f8b50..34756f70 100644
--- a/datastore/datastore-core/api/restricted_current.txt
+++ b/datastore/datastore-core/api/restricted_current.txt
@@ -22,11 +22,15 @@
}
public final class DataStoreFactory {
- ctor public DataStoreFactory();
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf());
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null);
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer);
+ field public static final androidx.datastore.DataStoreFactory INSTANCE;
+ }
+
+ public final class DataStoreFactoryKt {
+ method public static <T> androidx.datastore.DataStore<T> createDataStore(android.content.Context, String fileName, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
}
public interface Serializer<T> {
diff --git a/datastore/datastore-core/src/test/java/androidx/datastore/DataStoreFactoryTest.kt b/datastore/datastore-core/src/androidTest/java/androidx/datastore/DataStoreFactoryTest.kt
similarity index 62%
rename from datastore/datastore-core/src/test/java/androidx/datastore/DataStoreFactoryTest.kt
rename to datastore/datastore-core/src/androidTest/java/androidx/datastore/DataStoreFactoryTest.kt
index f58247c..6ea9d01 100644
--- a/datastore/datastore-core/src/test/java/androidx/datastore/DataStoreFactoryTest.kt
+++ b/datastore/datastore-core/src/androidTest/java/androidx/datastore/DataStoreFactoryTest.kt
@@ -16,7 +16,9 @@
package androidx.datastore
+import android.content.Context
import androidx.datastore.handlers.ReplaceFileCorruptionHandler
+import androidx.test.core.app.ApplicationProvider
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.TestCoroutineScope
@@ -37,17 +39,18 @@
private lateinit var testFile: File
private lateinit var dataStoreScope: TestCoroutineScope
+ private lateinit var context: Context
@Before
fun setUp() {
testFile = tmp.newFile()
dataStoreScope = TestCoroutineScope()
+ context = ApplicationProvider.getApplicationContext()
}
@Test
fun testNewInstance() = runBlockingTest {
- val factory = DataStoreFactory()
- val store = factory.create(
+ val store = DataStoreFactory.create(
produceFile = { testFile },
serializer = TestingSerializer(),
scope = dataStoreScope
@@ -65,9 +68,7 @@
fun testCorruptionHandlerInstalled() = runBlockingTest {
val valueToReplace = 123.toByte()
- val factory = DataStoreFactory()
-
- val store = factory.create(
+ val store = DataStoreFactory.create(
produceFile = { testFile },
serializer = TestingSerializer(failReadWithCorruptionException = true),
corruptionHandler = ReplaceFileCorruptionHandler<Byte> {
@@ -81,24 +82,22 @@
@Test
fun testMigrationsInstalled() = runBlockingTest {
- val factory = DataStoreFactory()
-
val migratedByte = 1
val migratePlus2 = object : DataMigration<Byte> {
- override suspend fun shouldMigrate(currentData: Byte) = true
- override suspend fun migrate(currentData: Byte) = currentData.inc().inc()
- override suspend fun cleanUp() {}
- }
+ override suspend fun shouldMigrate(currentData: Byte) = true
+ override suspend fun migrate(currentData: Byte) = currentData.inc().inc()
+ override suspend fun cleanUp() {}
+ }
val migrateMinus1 = object : DataMigration<Byte> {
- override suspend fun shouldMigrate(currentData: Byte) = true
+ override suspend fun shouldMigrate(currentData: Byte) = true
- override suspend fun migrate(currentData: Byte) = currentData.dec()
+ override suspend fun migrate(currentData: Byte) = currentData.dec()
- override suspend fun cleanUp() {}
- }
+ override suspend fun cleanUp() {}
+ }
- val store = factory.create(
+ val store = DataStoreFactory.create(
produceFile = { testFile },
migrations = listOf(migratePlus2, migrateMinus1),
scope = dataStoreScope,
@@ -107,4 +106,33 @@
assertThat(store.data.first()).isEqualTo(migratedByte)
}
+
+ @Test
+ fun testCreateWithContextAndName() = runBlockingTest {
+ val byte = 1
+
+ var store = context.createDataStore(
+ serializer = TestingSerializer(),
+ fileName = "my_settings.byte",
+ scope = dataStoreScope
+ )
+ store.updateData { 1 }
+
+ // Create it again and confirm it's still there
+ store = context.createDataStore(
+ serializer = TestingSerializer(),
+ fileName = "my_settings.byte",
+ scope = dataStoreScope
+ )
+ assertThat(store.data.first()).isEqualTo(byte)
+
+ // Check that the file name is context.filesDir + fileName
+ store = DataStoreFactory.create(
+ produceFile = {
+ File(context.filesDir, "datastore/my_settings.byte")
+ }, serializer = TestingSerializer(),
+ scope = dataStoreScope
+ )
+ assertThat(store.data.first()).isEqualTo(byte)
+ }
}
\ No newline at end of file
diff --git a/datastore/datastore-core/src/androidTest/java/migrations/SharedPreferencesMigrationTest.kt b/datastore/datastore-core/src/androidTest/java/androidx/datastore/migrations/SharedPreferencesMigrationTest.kt
similarity index 98%
rename from datastore/datastore-core/src/androidTest/java/migrations/SharedPreferencesMigrationTest.kt
rename to datastore/datastore-core/src/androidTest/java/androidx/datastore/migrations/SharedPreferencesMigrationTest.kt
index bb90413..73501f4 100644
--- a/datastore/datastore-core/src/androidTest/java/migrations/SharedPreferencesMigrationTest.kt
+++ b/datastore/datastore-core/src/androidTest/java/androidx/datastore/migrations/SharedPreferencesMigrationTest.kt
@@ -138,7 +138,7 @@
private fun getDataStoreWithMigrations(
migrations: List<DataMigration<Byte>>
): DataStore<Byte> {
- return DataStoreFactory().create(
+ return DataStoreFactory.create(
produceFile = { datastoreFile },
serializer = TestingSerializer(),
migrations = migrations,
diff --git a/datastore/datastore-core/src/main/java/androidx/datastore/DataStoreFactory.kt b/datastore/datastore-core/src/main/java/androidx/datastore/DataStoreFactory.kt
index 969495e..496e239 100644
--- a/datastore/datastore-core/src/main/java/androidx/datastore/DataStoreFactory.kt
+++ b/datastore/datastore-core/src/main/java/androidx/datastore/DataStoreFactory.kt
@@ -16,6 +16,7 @@
package androidx.datastore
+import android.content.Context
import androidx.datastore.handlers.NoOpCorruptionHandler
import androidx.datastore.handlers.ReplaceFileCorruptionHandler
import kotlinx.coroutines.CoroutineScope
@@ -26,7 +27,7 @@
/**
* Public factory for creating DataStore instances.
*/
-class DataStoreFactory {
+object DataStoreFactory {
/**
* Create an instance of SingleProcessDataStore. The user is responsible for ensuring that
* there is never more than one DataStore acting on a file at a time.
@@ -63,4 +64,34 @@
initTasksList = listOf(DataMigrationInitializer.getInitializer(migrations)),
scope = scope
)
-}
\ No newline at end of file
+}
+
+/**
+ * Create an instance of SingleProcessDataStore. The user is responsible for ensuring that
+ * there is never more than one instance of SingleProcessDataStore acting on a file at a time.
+ *
+ * @param fileName the filename relative to Context.filesDir that DataStore acts on. The File is
+ * obtained by calling File(context.filesDir, fileName). No two instances of DataStore should
+ * act on the same file at the same time.
+ * @param corruptionHandler The corruptionHandler is invoked if DataStore encounters a
+ * [CorruptionException] when attempting to read data. CorruptionExceptions are thrown by
+ * serializers when data can not be de-serialized.
+ * @param migrations are run before any access to data can occur. Each producer and migration
+ * may be run more than once whether or not it already succeeded (potentially because another
+ * migration failed or a write to disk failed.)
+ * @param scope The scope in which IO operations and transform functions will execute.
+ */
+fun <T> Context.createDataStore(
+ fileName: String,
+ serializer: Serializer<T>,
+ corruptionHandler: ReplaceFileCorruptionHandler<T>? = null,
+ migrations: List<DataMigration<T>> = listOf(),
+ scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
+): DataStore<T> =
+ DataStoreFactory.create(
+ produceFile = { File(this.filesDir, "datastore/$fileName") },
+ serializer = serializer,
+ corruptionHandler = corruptionHandler,
+ migrations = migrations,
+ scope = scope
+ )
diff --git a/datastore/datastore-preferences/api/api_lint.ignore b/datastore/datastore-preferences/api/api_lint.ignore
index 50dbca8..5586703 100644
--- a/datastore/datastore-preferences/api/api_lint.ignore
+++ b/datastore/datastore-preferences/api/api_lint.ignore
@@ -3,5 +3,5 @@
Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.datastore.preferences.Preferences.Builder.remove(String)
-MissingJvmstatic: androidx.datastore.preferences.SharedPreferencesToPreferencesKt#SharedPreferencesMigration(android.content.Context, String, java.util.Set<java.lang.String>, boolean):
+MissingJvmstatic: androidx.datastore.preferences.PreferenceDataStoreFactory#create(kotlin.jvm.functions.Function0<? extends java.io.File>, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>>, kotlinx.coroutines.CoroutineScope):
A Kotlin method with default parameter values should be annotated with @JvmOverloads for better Java interoperability; see https://android.github.io/kotlin-guides/interop.html#function-overloads-for-defaults
diff --git a/datastore/datastore-preferences/api/current.txt b/datastore/datastore-preferences/api/current.txt
index 217726b..2242287 100644
--- a/datastore/datastore-preferences/api/current.txt
+++ b/datastore/datastore-preferences/api/current.txt
@@ -2,11 +2,12 @@
package androidx.datastore.preferences {
public final class PreferenceDataStoreFactory {
- ctor public PreferenceDataStoreFactory();
method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf());
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null);
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile);
+ field public static final androidx.datastore.preferences.PreferenceDataStoreFactory INSTANCE;
+ }
+
+ public final class PreferenceDataStoreFactoryKt {
+ method public static androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> createDataStore(android.content.Context, String name, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
}
public final class Preferences {
diff --git a/datastore/datastore-preferences/api/public_plus_experimental_current.txt b/datastore/datastore-preferences/api/public_plus_experimental_current.txt
index 217726b..2242287 100644
--- a/datastore/datastore-preferences/api/public_plus_experimental_current.txt
+++ b/datastore/datastore-preferences/api/public_plus_experimental_current.txt
@@ -2,11 +2,12 @@
package androidx.datastore.preferences {
public final class PreferenceDataStoreFactory {
- ctor public PreferenceDataStoreFactory();
method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf());
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null);
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile);
+ field public static final androidx.datastore.preferences.PreferenceDataStoreFactory INSTANCE;
+ }
+
+ public final class PreferenceDataStoreFactoryKt {
+ method public static androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> createDataStore(android.content.Context, String name, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
}
public final class Preferences {
diff --git a/datastore/datastore-preferences/api/restricted_current.txt b/datastore/datastore-preferences/api/restricted_current.txt
index 217726b..2242287 100644
--- a/datastore/datastore-preferences/api/restricted_current.txt
+++ b/datastore/datastore-preferences/api/restricted_current.txt
@@ -2,11 +2,12 @@
package androidx.datastore.preferences {
public final class PreferenceDataStoreFactory {
- ctor public PreferenceDataStoreFactory();
method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf());
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null);
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile);
+ field public static final androidx.datastore.preferences.PreferenceDataStoreFactory INSTANCE;
+ }
+
+ public final class PreferenceDataStoreFactoryKt {
+ method public static androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> createDataStore(android.content.Context, String name, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
}
public final class Preferences {
diff --git a/datastore/datastore-preferences/src/test/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt b/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
similarity index 76%
rename from datastore/datastore-preferences/src/test/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
rename to datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
index 7ae14dc..1b26243 100644
--- a/datastore/datastore-preferences/src/test/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
+++ b/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
@@ -16,8 +16,10 @@
package androidx.datastore.preferences
+import android.content.Context
import androidx.datastore.DataMigration
import androidx.datastore.handlers.ReplaceFileCorruptionHandler
+import androidx.test.core.app.ApplicationProvider
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.flow.first
@@ -39,17 +41,18 @@
private lateinit var testFile: File
private lateinit var dataStoreScope: TestCoroutineScope
+ private lateinit var context: Context
@Before
fun setUp() {
testFile = tmp.newFile("test_file." + PreferencesSerializer.fileExtension)
dataStoreScope = TestCoroutineScope()
+ context = ApplicationProvider.getApplicationContext()
}
@Test
fun testNewInstance() = runBlockingTest {
- val factory = PreferenceDataStoreFactory()
- val store = factory.create(
+ val store = PreferenceDataStoreFactory.create(
produceFile = { testFile },
scope = dataStoreScope
)
@@ -68,11 +71,9 @@
fun testCorruptionHandlerInstalled() = runBlockingTest {
testFile.writeBytes(byteArrayOf(0x00, 0x00, 0x00, 0x03)) // Protos can not start with 0x00.
- val factory = PreferenceDataStoreFactory()
-
val valueToReplace = Preferences.Builder().setBoolean("key", true).build()
- val store = factory.create(
+ val store = PreferenceDataStoreFactory.create(
produceFile = { testFile },
corruptionHandler = ReplaceFileCorruptionHandler<Preferences> {
valueToReplace
@@ -84,7 +85,6 @@
@Test
fun testMigrationsInstalled() = runBlockingTest {
- val factory = PreferenceDataStoreFactory()
val expectedPreferences = Preferences.Builder()
.setString("string_key", "value")
@@ -109,7 +109,7 @@
override suspend fun cleanUp() {}
}
- val store = factory.create(
+ val store = PreferenceDataStoreFactory.create(
produceFile = { testFile },
migrations = listOf(migrateTo5, migratePlus1),
scope = dataStoreScope
@@ -117,4 +117,25 @@
assertEquals(expectedPreferences, store.data.first())
}
+
+ @Test
+ fun testCreateWithContextAndName() = runBlockingTest {
+ val prefs = Preferences.Builder().setInt("int_key", 12345).build()
+
+ var store = context.createDataStore(
+ name = "my_settings",
+ scope = dataStoreScope
+ )
+ store.updateData { prefs }
+
+ // Create it again and confirm it's still there
+ store = context.createDataStore("my_settings", scope = dataStoreScope)
+ assertEquals(prefs, store.data.first())
+
+ // Check that the file name is context.filesDir + name + ".preferences_pb"
+ store = PreferenceDataStoreFactory.create(produceFile = {
+ File(context.filesDir, "datastore/my_settings.preferences_pb")
+ }, scope = dataStoreScope)
+ assertEquals(prefs, store.data.first())
+ }
}
\ No newline at end of file
diff --git a/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/SharedPreferencesToPreferencesTest.kt b/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/SharedPreferencesToPreferencesTest.kt
index c92da6e..cc02e8a 100644
--- a/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/SharedPreferencesToPreferencesTest.kt
+++ b/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/SharedPreferencesToPreferencesTest.kt
@@ -393,7 +393,7 @@
private fun getDataStoreWithMigrations(
migrations: List<DataMigration<Preferences>>
): DataStore<Preferences> {
- return PreferenceDataStoreFactory().create(
+ return PreferenceDataStoreFactory.create(
produceFile = { datastoreFile },
migrations = migrations,
scope = TestCoroutineScope()
diff --git a/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt b/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt
index 7de4135..f03680d 100644
--- a/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt
+++ b/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt
@@ -16,6 +16,7 @@
package androidx.datastore.preferences
+import android.content.Context
import androidx.datastore.CorruptionException
import androidx.datastore.DataMigration
import androidx.datastore.DataStore
@@ -29,33 +30,30 @@
/**
* Public factory for creating PreferenceDataStore instances.
*/
-class PreferenceDataStoreFactory {
- private val dataStoreFactory = DataStoreFactory()
-
+object PreferenceDataStoreFactory {
/**
* Create an instance of SingleProcessDataStore. The user is responsible for ensuring that
* there is never more than one instance of SingleProcessDataStore acting on a file at a time.
*
- * @param produceFile Function which returns the file that the new DataStore will act on. The function
- * must return the same path every time. No two instances of PreferenceDataStore
+ * @param produceFile Function which returns the file that the new DataStore will act on.
+ * The function must return the same path every time. No two instances of PreferenceDataStore
* should act on the same file at the same time. The file must have the extension
* preferences_pb.
- * @param corruptionHandler The corruptionHandler is invoked if DataStore encounters a [CorruptionException] when
- * attempting to read data. CorruptionExceptions are thrown by serializers when data can
- * not be de-serialized.
- * @param migrations are run before any access to data can occur. Each
- * producer and migration may be run more than once whether or not it already succeeded
- * (potentially because another migration failed or a write to disk failed.)
+ * @param corruptionHandler The corruptionHandler is invoked if DataStore encounters a
+ * [CorruptionException] when attempting to read data. CorruptionExceptions are thrown by
+ * serializers when data cannot be de-serialized.
+ * @param migrations are run before any access to data can occur. Each producer and migration
+ * may be run more than once whether or not it already succeeded (potentially because another
+ * migration failed or a write to disk failed.)
* @param scope The scope in which IO operations and transform functions will execute.
*/
- @JvmOverloads // Generate methods for default params for java users.
fun create(
produceFile: () -> File,
corruptionHandler: ReplaceFileCorruptionHandler<Preferences>? = null,
migrations: List<DataMigration<Preferences>> = listOf(),
scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
): DataStore<Preferences> =
- dataStoreFactory.create(
+ DataStoreFactory.create(
produceFile = {
val file = produceFile()
check(file.extension == PreferencesSerializer.fileExtension) {
@@ -69,4 +67,33 @@
migrations = migrations,
scope = scope
)
-}
\ No newline at end of file
+}
+
+/**
+ * Create an instance of SingleProcessDataStore. The user is responsible for ensuring that
+ * there is never more than one instance of SingleProcessDataStore acting on a file at a time.
+ *
+ * @param name The name of the preferences. The preferences will be stored in a file obtained
+ * by calling: File(context.filesDir, "datastore/" + name + ".preferences_pb")
+ * @param corruptionHandler The corruptionHandler is invoked if DataStore encounters a
+ * [CorruptionException] when attempting to read data. CorruptionExceptions are thrown by
+ * serializers when data can not be de-serialized.
+ * @param migrations are run before any access to data can occur. Each producer and migration
+ * may be run more than once whether or not it already succeeded (potentially because another
+ * migration failed or a write to disk failed.)
+ * @param scope The scope in which IO operations and transform functions will execute.
+ */
+fun Context.createDataStore(
+ name: String,
+ corruptionHandler: ReplaceFileCorruptionHandler<Preferences>? = null,
+ migrations: List<DataMigration<Preferences>> = listOf(),
+ scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
+): DataStore<Preferences> =
+ PreferenceDataStoreFactory.create(
+ produceFile = {
+ File(this.filesDir, "datastore/$name.preferences_pb")
+ },
+ corruptionHandler = corruptionHandler,
+ migrations = migrations,
+ scope = scope
+ )
diff --git a/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/PreferencesDataStoreActivity.kt b/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/PreferencesDataStoreActivity.kt
index d36e21b..65b3a74 100644
--- a/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/PreferencesDataStoreActivity.kt
+++ b/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/PreferencesDataStoreActivity.kt
@@ -24,27 +24,25 @@
import androidx.annotation.Sampled
import androidx.appcompat.app.AppCompatActivity
import androidx.datastore.DataStore
-import androidx.datastore.preferences.PreferenceDataStoreFactory
import androidx.datastore.preferences.Preferences
+import androidx.datastore.preferences.createDataStore
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
-import java.io.File
import java.io.IOException
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
class PreferencesDataStoreActivity : AppCompatActivity() {
private val TAG = "PreferencesActivity"
- private val PREFERENCE_STORE_FILE_NAME = "datastore_test_app.preferences_pb"
+ private val PREFERENCE_STORE_FILE_NAME = "datastore_test_app"
private val COUNTER_KEY = "counter"
private val preferenceStore: DataStore<Preferences> by lazy {
- PreferenceDataStoreFactory().create(
- { File(applicationContext.filesDir, PREFERENCE_STORE_FILE_NAME) })
+ applicationContext.createDataStore(PREFERENCE_STORE_FILE_NAME)
}
@Sampled
diff --git a/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/ProtoDataStoreActivity.kt b/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/ProtoDataStoreActivity.kt
index 57d6411..8b46d26 100644
--- a/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/ProtoDataStoreActivity.kt
+++ b/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/ProtoDataStoreActivity.kt
@@ -46,7 +46,7 @@
private val PROTO_STORE_FILE_NAME = "datastore_test_app.pb"
private val settingsStore: DataStore<Settings> by lazy {
- DataStoreFactory().create(
+ DataStoreFactory.create(
{ File(applicationContext.filesDir, PROTO_STORE_FILE_NAME) },
SettingsSerializer
)
diff --git a/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/SettingsFragment.kt b/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/SettingsFragment.kt
index cd4966f..b2e8d2b 100644
--- a/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/SettingsFragment.kt
+++ b/datastore/datastore-sampleapp/src/main/java/com/example/datastoresampleapp/SettingsFragment.kt
@@ -69,7 +69,7 @@
private val PROTO_STORE_FILE_NAME = "datastore_test_app.pb"
private val settingsStore: DataStore<Settings> by lazy {
- DataStoreFactory().create(
+ DataStoreFactory.create(
{ File(requireActivity().applicationContext.filesDir, PROTO_STORE_FILE_NAME) },
SettingsSerializer
)